Android NDK系列- 文件拆分与合并
Posted SingleShu888
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
以上是关于Android NDK系列- 文件拆分与合并的主要内容,如果未能解决你的问题,请参考以下文章
Android NDK系列- AS导入so三方库,使用C/C+方法
Android NDK系列- AS导入so三方库,使用C/C+方法
Android NDK系列-AS生成jar包导入so库并使用方法