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);
}
上面是文件合并的实现,别忘记指针的释放。