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 JNICALLJava_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 JNICALLJava_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. 万字长文带你了解最常用的开源 Squid 代理服务器
  2. 一款常用的 Squid 日志分析工具
  3. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  4. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  5. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  6. 给Unity的Android工程加上广告代码(1)
  7. Android(安卓)SAX方式解析XML文件
  8. android spinner 样式完全自定义[包括RadioButton和RatingBar效
  9. Android三种绑定Service方式的demo

随机推荐

  1. Android(安卓)6.0 通话记录生成保存和读
  2. 【Android】Navigation 用法及源码解析
  3. 提高代码质量-工具篇
  4. Android跨进程通信IPC之6——Parcel--Bin
  5. 图解,Eclipse+ADT+ScalaIDE用Scala写Andro
  6. Android(安卓)WebView 精简Demo
  7. Android(安卓)项目 sdk导入腾讯云cos:
  8. OkHttp3实现原理
  9. Retrofit学习笔记(一)
  10. Android开发-HUAWEI DevEco Studio工具