JNI中對文件的操作是很方便的,也是比較常用,主要使用到fopen以及fputc、fgetc等
//獲取sdcard路徑
private static final String SD_CARD_PATH= Environment.getExternalStorageDirectory().getAbsolutePath();
本地函數聲明:
public class FileUtils {
public static native void diff(String path, String pattern_Path, int num);
public static native void patch(String path, String pattern_Path, int num);
static {
System.loadLibrary("native-lib");
}
}
上面兩個函數,分別負責文件的拆分與合併,diff函數的第一個參數表示源文件路徑,第二個參數表示拆分文件的路徑,第三個參數表示拆分文件的個數,patch合併函數類似。下面在c中實現兩個native函數。
extern "C"
JNIEXPORT void JNICALL native_diff(JNIEnv *env, jclass type,
jstring path_, jstring pattern_Path_,
jint file_num) {
//首先將jstring轉換成char*
const char *path = env->GetStringUTFChars(path_, 0);
const char *pattern_Path = env->GetStringUTFChars(pattern_Path_, 0);
LOGD("JNI native diff Begin");
//申請一個二維數組 用於存放子文件的名字 二級指針就是二維數組
char ** patches= (char **) malloc(sizeof(char*) * file_num);
for (int i = 0; i < file_num; i++) {
//爲每一個文件名字申請地址
LOGD("char = %d char * = %d", sizeof(char), sizeof(char*));
patches[i]= (char *) malloc(sizeof(char) * 100);
// 需要分割的文件 vab.mp4
// 每個子文件名稱 vab_n.mp4
sprintf(patches[i],pattern_Path,i); //對字符數組進行格式化,將格式結果存放在第一個裏邊,對第二個進行格式化,使用第三個參數進行傳參
LOGD("path path is %s",patches[i]);
}
//獲取被拆分文件的大小
int file_size=get_file_size(path);
if(file_size==0){
LOGD("獲取原文件大小失敗");
return ;
}
LOGD("file size is %d",file_size);
FILE* fpr=fopen(path,"rb"); //以讀的方式打開 打開 原文件
/*
* 判斷文件是否能被file_num 整除
* 能整除就平分
* 不能整除就先平分file_num-1
* */
if (file_size% file_num==0){ //能平分的情況
LOGD("均分");
int part=file_size / file_num;
LOGD("part is %d",part);
for (int i = 0; i <file_num ; i++) {
FILE* fpw=fopen(patches[i],"wb"); //以只寫的方式打開,如果存在就講文件刪除 只負責寫數據
for (int j = 0; j < part; j++) { //這裏分別向各個部分進行寫數據 但是 如何記錄寫數據的起點 是不是根據文件的遊標的移動
fputc(fgetc(fpr), fpw);
}
fclose(fpw); //關閉文件指針
}
}else{// 不能平分
LOGD("不均分");
int part = file_size / (file_num - 1);
LOGD("part is %d",part);
for (int i = 0; i < file_num-1; i++) {
FILE * fpw=fopen(patches[i],"wb"); //待寫入的文件指針
for (int j = 0; j <part ; j++) {
fputc(fgetc(fpr),fpw);
}
fclose(fpw);
}
FILE * fpw=fopen(patches[file_num-1],"wb");
for (int i = 0; i <file_size%(file_num-1) ; i++) {
fputc(fgetc(fpr),fpw);
}
fclose(fpw);
}
fclose(fpr);
for (int i =0; i< file_num; i++) {
free(patches[i]); //一個malloc對應一個free
}
free(patches);
env->ReleaseStringUTFChars(path_, path);
env->ReleaseStringUTFChars(pattern_Path_, pattern_Path);
}
這裏的native_diff是動態註冊的,對應的diff函數,不熟悉動態註冊的,可以先讀上一篇。上面對的diff主要負責文件拆分,主要的思路是,先嚐試將文件均分成file_num份,如果能均分直接均分,然後分別寫在子文件,如果不能均分,先均分file_num-1份,剩下的部分放在最後一個文件。
extern "C"
JNIEXPORT void JNICALL native_patch(JNIEnv *env, jclass type,
jstring merge_path, jstring pattern_Path_,
jint file_num) {
//首先將jstring轉換成char*
const char *path = env->GetStringUTFChars(merge_path, 0);
const char *pattern_Path = env->GetStringUTFChars(pattern_Path_, 0);
LOGD("JNI native patch Begin");
//申請一個二維數組 用於存放子文件的名字 二級指針就是二維數組
char ** patches= (char **) malloc(sizeof(char*) * file_num);
for (int i = 0; i < file_num; i++) {
//爲每一個文件名字申請地址
LOGD("char = %d char * = %d", sizeof(char), sizeof(char*));
patches[i]= (char *) malloc(sizeof(char) * 100);
// 需要分割的文件 vab.mp4
// 每個子文件名稱 vab_n.mp4
sprintf(patches[i],pattern_Path,i); //對字符數組進行格式化,將格式結果存放在第一個裏邊,對第二個進行格式化,使用第三個參數進行傳參
LOGD("path path is %s",patches[i]);
}
FILE * fpw=fopen(path,"wb"); //在這個文件裏邊寫數據
for (int i = 0; i < file_num; i++) {
FILE *fpr=fopen(patches[i],"rb");
int fileSize=get_file_size(patches[i]);
for (int i = 0; i <fileSize ; ++i) {
fputc(fgetc(fpr),fpw);
}
fclose(fpr);
}
fclose(fpw);
for (int i = 0; i <file_num ; i++) {
free(patches[i]); //每一個malloc對應一個free
}
env->ReleaseStringUTFChars(merge_path, path);
env->ReleaseStringUTFChars(pattern_Path_, pattern_Path);
}
上面是文件合併的實現,別忘記指針的釋放。