NDK基础三 JNI 文件拆分

本文详细介绍使用JNI在Java和C之间桥接,实现文件的拆分与合并功能。通过JNI调用C语言的fopen、fputc和fgetc等函数,对文件进行高效操作。文章深入解析了diff和patch函数的实现细节,包括文件均分和平分策略,以及如何在不同情况下处理文件的读写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

上面是文件合并的实现,别忘记指针的释放。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值