NDK基礎三 JNI 文件拆分

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);
}

上面是文件合併的實現,別忘記指針的釋放。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章