Android NDK系列(六)- 文件拆分与合并

NDK系列(一)-AS使用javah生成so文件
NDK系列(二)-AS使用CmakeLists生成so文件
NDK系列(三)-AS编写C文件没有提示和不识别NULL
NDK系列(四)-AS生成jar包、导入so库并使用方法
NDK系列(五)- AS导入so三方库,使用C/C+方法

文件的拆分和合并是一个常见的功能,使用java是可以完成的。
Android合并文件的三种方式 ,通过FileOutputStream、与FileInputStream方式,通过FileChannel方式,通过RandomAccessFile方式。还可以使用C来拆分和合并文件,这是一个效率很高的方式。至于java和C需要哪种来实现完全看自己的需求。下面参考一篇C的文件拆分合并代码。C语言学习笔记之文件的分割与合并


第一步:理清文件拆分和合并的逻辑
1,首先需要拆分文件的地址,生成拆分后子文件的地址,子文件(可以使用原文件名_%d命名,然后在代码中进行替换,如果嫌麻烦也可以直接用传入多个地址是一样的)。
2,需要知道拆分的子文件个数
3,源文件的大小,以及是否能整除子文件个数(这里分两种情况处理)
4,读取源文件,循环写入子文件。(这里拆分需要一个个char读取和写入,不然会出问题)
5,关闭文件流,释放资源
6,合并逻辑和拆分逻辑类似,只是读取子文件数据,写入源文件。

这里写图片描述


第二步:代码阶段

首先创建一个C++的 Android项目(这个在之前有介绍),这个很简单,删掉自动生成的jni方法。

这里写图片描述

需要申明两个native方法,一个拆分文件,一个合并文件,传入的参数都是一样的。在这个项目中不需要修改cmakelists文件,没有导入其他so文件,当然你要想把这个生成so自己留着用,也是可以的。那么具体逻辑在cpp文件中实现。

这里写图片描述
调试的时候需要打印数据,那么申明一个打印方法。先做好准备工作,首先需要一个方法来获取一个文件的大小值。

long get_file_size(const char* path) {
    FILE *fp = fopen(path, "rb"); //打开一个文件, 文件必须存在,只运行读
    fseek(fp, 0, SEEK_END);
    long ret = ftell(fp);
    fclose(fp);
    return ret;
}

这是C里面打开一个文件,读取一个文件大小。

JNIEXPORT void JNICALL
Java_com_example_administrator_jnidiffdemo_MainActivity_splitFile ( JNIEnv * env ,
                                                                    jobject instance ,
                                                                    jstring srcFilePath_ ,
                                                                    jstring dstFilePath_ ,
                                                                    jint file_num ) {
    //    1,首先需要拆分文件的地址,生成拆分后子文件的地址,子文件(可以使用原文件名_%d命名,然后在代码中进行替换,如果嫌麻烦也可以直接用传入多个地址是一样的)。
//2,需要知道拆分的子文件个数
    const char * srcFilePath = env -> GetStringUTFChars ( srcFilePath_ , NULL );
    const char * dstFilePath = env -> GetStringUTFChars ( dstFilePath_ , NULL );

    LOGI( "JNI native diff begin" );
    //申请存放多个文件的内存  二级指针首地址
    char ** patches = ( char ** ) malloc ( sizeof ( char * ) * file_num );

    for ( int i = 0 ; i < file_num ; i ++ ) {
        patches[ i ] = ( char * ) malloc ( sizeof ( char ) * 100 );
        //对每个地址进行拼接
        sprintf ( patches[ i ] , dstFilePath , i );
        LOGI( "patch path : %s" , patches[ i ] );
    }

//  3,源文件的大小,以及是否能整除子文件个数(这里分两种情况处理) 读取源文件大小  根据大小进行拆分
    int fileSize = get_file_size ( srcFilePath );
    LOGI( "fileSize : %d" , fileSize );
//    打开源文件
    FILE * rfp = fopen ( srcFilePath , "rb" );
//   4,读取源文件,循环写入子文件。(这里拆分需要一个个char读取和写入,不然会出问题) 源文件是否正好整除所划分的文件个数  分别处理
    if ( fileSize % file_num == 0 ) {
        int part = fileSize / file_num;
        for ( int i = 0 ; i < file_num ; i ++ ) {
            FILE * fwp = fopen ( patches[ i ] , "wb" );
            for ( int j = 0 ; j < part ; j ++ ) {
                fputc ( fgetc ( rfp ) , fwp );
            }
            fclose ( fwp );
        }
    } else {
        int part = fileSize / ( file_num - 1 );
        for ( int i = 0 ; i < file_num - 1 ; i ++ ) {
            FILE * fwp = fopen ( patches[ i ] , "wb" );
            for ( int j = 0 ; j < part ; j ++ ) {
                fputc ( fgetc ( rfp ) , fwp );
            }
            fclose ( fwp );
        }
        FILE * fwp = fopen ( patches[ file_num - 1 ] , "wb" );
        for ( int i = 0 ; i < fileSize % ( file_num - 1 ) ; i ++ ) {
            fputc ( fgetc ( rfp ) , fwp );
        }
        fclose ( fwp );
    }
//  5,关闭文件流,释放资源
    fclose ( rfp );
    for ( int i = 0 ; i < file_num ; i ++ ) {
        free ( patches[ i ] );
    }
    free ( patches );

    env -> ReleaseStringUTFChars ( srcFilePath_ , srcFilePath );
    env -> ReleaseStringUTFChars ( dstFilePath_ , dstFilePath );
}

这里的逻辑都有注释,按照之前写的5步逻辑,那么合并就相对于简单了

JNIEXPORT void JNICALL
Java_com_example_administrator_jnidiffdemo_MainActivity_mergeFile ( JNIEnv * env ,
                                                                    jobject instance ,
                                                                    jstring srcFilePath_ ,
                                                                    jstring dstFilePath_ ,
                                                                    jint fileNum ) {
    const char * srcFilePath = env -> GetStringUTFChars ( srcFilePath_ , 0 );
    const char * dstFilePath = env -> GetStringUTFChars ( dstFilePath_ , 0 );

    char** patches = ( char**)malloc ( sizeof ( char*)*fileNum);
    for ( int i = 0 ; i < fileNum ;  i++ ) {
        patches[i] = (char*)malloc ( sizeof ( char)*100);
        sprintf (patches[i],dstFilePath,i);
        LOGI("patches[i]:%s",patches[i]);
    }

    FILE *fwp = fopen (srcFilePath,"wb");

    for ( int i = 0 ; i < fileNum ; i++ ) {
        int fileSize = get_file_size (patches[i]);
        FILE *frp = fopen (patches[i],"rb");
        LOGI("fileSize:%d",fileSize);
        for ( int j = 0 ; j < fileSize ; j++ ) {
            fputc (fgetc (frp),fwp);
        }
        fclose (frp);
    }
    fclose (fwp);

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

    env -> ReleaseStringUTFChars ( srcFilePath_ , srcFilePath );
    env -> ReleaseStringUTFChars ( dstFilePath_ , dstFilePath );
}

在MainActivity调用。

 public void split(View View){
        String srcFile = SD_DIR+"/"+"a.mp4";
        String dstFile = SD_DIR+"/"+"a_%d.mp4";
        splitFile(srcFile,dstFile,4);
    }

    public void merge(View view){
        String srcFile = SD_DIR+"/"+"a.mp4";
        String dstFile = SD_DIR+"/"+"a_%d.mp4";
        mergeFile(srcFile,dstFile,4);
    }

基本就这些了,只要踏入了门槛,其他的都是C的知识多一点,不会的也可以在网上查。
github地址:https://github.com/SingleShu/JniDiffDemo

感谢动脑学院NDK专题资源

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值