NDK实战(三)—— 文件的拆分与合并

本文详细介绍了如何使用NDK进行文件的拆分和合并操作。首先在Java层声明了一个native方法,然后在C代码中实现文件拆分,通过预设的a.mp4文件,执行后得到a_0.mp4、a_1.mp4、a_2.mp4等三个拆分文件。接着,文章探讨了如何进行文件的合并操作。
摘要由CSDN通过智能技术生成

一、文件拆分

先在Java层声明一个native方法

public static native void diff(String path, String patternPath, int fileNum);

其对应的调用(Kotlin)

 private val SDK_CARD_PATH = Environment.getExternalStorageDirectory().absolutePath
 
 val path = SDK_CARD_PATH + File.separator + "a.mp4"
        val patternPath = SDK_CARD_PATH + File.separator + "a_%d.mp4"//%d可在native层用数字替代
        FileUtils.diff(path, patternPath, 3)

接下来是 C 代码

获取文件大小

long getFileSize(char *__path) {
    FILE *fp = fopen(__path, "rb");//打开一个文件,只允许读
    fseek(fp, 0, SEEK_END);//游标从0到结束,表示整个文件
    long size = ftell(fp);
    fclose(fp);
    return size;
}
//方法名已用动态注册
JNIEXPORT void JNICALL
jni_diff(JNIEnv *env, jclass type, jstring path_,
         jstring patternPath_, jint fileNum) {
    const char *path = (*env)->GetStringUTFChars(env, path_, 0);
    const char *patternPath = (*env)->GetStringUTFChars(env, patternPath_, 0);
    LogI("JNI Begin");

    //申请一个二维数组用来存放子文件的绝对路径,指针可以用来表示数组,数组里的内容是char*,所以这里是二维数组
    char **patchPathArray = malloc(sizeof(char *) * fileNum);

    for (int i = 0; i < fileNum; ++i) {
        //此处偷工减料一下,假设每个文件名的大小不会超过 sizeof(char) * 50
        patchPathArray[i] = (char)malloc(sizeof(char*)*50);
        //Java层传入的是地址 .../a_%d.mp4,此处会将文件命名为 .../a_0.mp4 , .../a_1.mp4 以此类推
        sprintf(patchPathArray[i], patternPath,
                i);

        LogI("patch path : %s", patchPathArray[i]);//打印一下地址
    }

    long fileSize = getFileSize(path);

    FILE *fpr = fopen(path, "rb");

    if (fileSize % fileNum == 0) {//如果整除的情况下
        long subFileSize = fileSize / fileNum;//每个子文件的大小
        for (int i = 0; i < fileNum; i++) {
            FILE *fpw = fopen(patchPathArray[i], "wb");//若文件不存在则创建,文件存在则覆写,只允许写
            for (long j = 0; j < subFileSize; j++) {
                fputc(fgetc(fpr), fpw);//fgetc方法:每次读取一个字节,光标就移动到该字节的尾部
            }
            fclose(fpw);
        }
    } else {//如果不整除的情况下
        //一开始不用 fileNum-1 是为了避免 fileNum-1 的情况下发生整除而导致最后一个文件size为0
        long subFileSize = fileSize / (fileNum - 1);

        for (int i = 0; i < fileNum - 1; i++) {
            FILE *fpw = fopen(patchPathArray[i], "wb");
            for (int j = 0; j < subFileSize; j++) {
                fputc(fgetc(fpr), fpw);
            }
            fclose(fpw);
        }

        long lastFileSize = fileSize % (fileNum - 1);
        FILE *fpw = fopen(patchPathArray[fileNum - 1], "wb");
        for (int i = 0; i < lastFileSize; ++i) {
            fputc(fgetc(fpr), fpw);
        }
        fclose(fpw);
    }

    for (int i = 0; i < fileNum; i++) {
        free(patchPathArray[i]);//释放所有路径的内存
    }

    free(patchPathArray);//释放二维数组的内存
    fclose(fpr);

    (*env)->ReleaseStringUTFChars(env, path_, path);
    (*env)->ReleaseStringUTFChars(env, patternPath_, patternPath);
}

预先在SD卡根目录下放入a.mp4,执行完java层代码后(记得加入SD卡读写权限),可以获得a_0.mp4、a_1.mp4、a_2.mp4 等三个文件

二、文件合并

JNIEXPORT void JNICALL
jni_patch(JNIEnv *env, jclass type, jstring mergePath_,
          jstring patternPath_, jint fileNum) {
    const char *mergePath = (*env)->GetStringUTFChars(env, mergePath_, 0);
    const char *patternPath = (*env)->GetStringUTFChars(env, patternPath_, 0);

    char **pathArray = (char **) malloc(sizeof(char *) * fileNum);

    for (int i = 0; i < fileNum; i++) {
        pathArray[i] = (char *) malloc(sizeof(char) * 50);
        sprintf(pathArray[i], patternPath, i);
    }

    FILE *fpw = fopen(mergePath, "wb");

    for (int i = 0; i < fileNum; i++) {
        long fileSize = getFileSize(pathArray[i]);
        FILE *fpr = fopen(pathArray[i], "rb");
        for (int j = 0; j < fileSize; j++) {
            putc(getc(fpr), fpw);
        }
        fclose(fpr);
    }

    fclose(fpw);

    for (int i = 0; i < fileNum; i++) {
        free(pathArray[i]);
    }

    free(pathArray);
    (*env)->ReleaseStringUTFChars(env, mergePath_, mergePath);
    (*env)->ReleaseStringUTFChars(env, patternPath_, patternPath);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值