JNI开发基础系列--文件切割和文件合并

文件切割和文件合并

文件切割思想:

首先计算出一个文件的大小,根据需要切割的份数计算出每份的大小,假如文件的长度为size,需要分割成n份。那么会有2种情况:

  • 当size能被n整除时,即size%n = 0,每份的大小为:size/n
  • 当size不能被n整除时,那么我们计算的思想是这样的,首先让前面(n-1)份进行均分,每份大小为size/(n-1),剩下的没分割玩的留给最后一份,最后一份的大小即size%(n-1),也即size-size*(n-1)

说了这么多废话,还是有点绕,不是很好理解,举个例子帮助理解一下:
比如文件的长度为101,需要切割成4分,显然101%4 = 1,那么就先均分3份
前面3份每份大小为101/3 =33,余数会在转换是抹掉,最后一份的大小就为2

文件合并就没啥说的了,把之前切割的字文件拼接起来组成一个完整的文件

准备工作,在手机sd卡根目录放一个mp3我这里放了一个cd.mp3,至于动态授权就需要自己去申请,不然会报错。

理解了原理之后直接上代码:

java中定义一个类FileUtils,并声明两个native方法

package com.cool.ndktest2;

/**
 * Created by cool on 2017/8/17.
 */

public class FileUtils {

    /**
     * 文件切割
     * @param path 要切割文件的路径
     * @param pattern 文件切割后名字的占位符
     * @param num 文件切割的数量
     */
    public native void diff(String path,String pattern,int num);

    /**
     * 文件合并
     * @param patchPath 合并后的路径
     * @param pattern 文件切割后名字的占位符
     * @param num 之前切割的数量
     */
    public native void patch(String patchPath,String pattern,int num);
}

java中使用

...
省略so库加载代码
...
private String path = Environment.getExternalStorageDirectory().getPath();

//文件分割方法
public void diff(View view){
        FileUtils fileUtils = new FileUtils();
        String mp3Path = path + "/cd.mp3";
        String path_pattern = path + "/cd_%d.mp3";
        fileUtils.diff(mp3Path,path_pattern,4);
    }

//文件合并方法
 public void patch(View view){
        FileUtils fileUtils = new FileUtils();
        String mp3Path = path + "/cdpatch.mp3";
        String path_pattern = path + "/cd_%d.mp3";
        fileUtils.patch(mp3Path,path_pattern,4);
    }

文件的分割合并的代码都是在c中实现,接下来把目光转向c中,里面每行的注释都非常的清楚

//
// Created by cool on 2017/8/16.
//

#include "com_cool_ndktest2_MainActivity.h"
#include <string.h>
#include <android/log.h>
#include <assert.h>
#include <malloc.h>

#define TAG "399"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))

//返回文件的大小
long getFileLenth(char *filePath){
    FILE *fp = fopen(filePath,"rb");
    fseek(fp,0L,SEEK_END);
    long lenth = ftell(fp);
    fclose(fp);
    return lenth;
}

//文件切割
JNIEXPORT void JNICALL native_diff
        (JNIEnv *env, jclass clazz, jstring jpath, jstring jpattern_path, jint jfile_num)
{
    LOGE("文件开始切割");
    const char* path = (*env)->GetStringUTFChars(env,jpath,NULL);
    const char* pattern = (*env)->GetStringUTFChars(env,jpattern_path,NULL);

    //申请二维数组存放切割后的文件名字
    char** patchs = (char**)malloc(sizeof(char*)*jfile_num);
    //分配内存
    for(int i = 0;i<jfile_num;i++){
        patchs[i] = malloc(sizeof(char)*100);
        sprintf(patchs[i],pattern,i);
        LOGE("每段文件的名字:%s",patchs[i]);
    }
    //计算文件长度
    long length = getFileLenth(path);
    LOGE("文件长度:%ld",length);
    //以读的权限打开文件流
    FILE* fp = fopen(path,"rb");

    //文件总长度对要切割的分数取模运算
    int size = length%jfile_num;
    if(size ==0){//刚好能够被整除
        //计算切分的每部分大小
        int patchSize = length/jfile_num;
        for (int i = 0; i < jfile_num; ++i) {
            //打开之前要切割的文件,以写入的方式打开文件
            FILE *patch = fopen(patchs[i],"wb");//若文件已经存在 就删除,只运行写
            for (int j = 0; j < patchSize; j++) {
                char ch = fgetc(fp);
                fputc(ch,patch);
            }
            fclose(patch);
        }

    } else{//不能被整除
        //计算切分的每部分大小
        int patchSize = length/(jfile_num-1);

        for (int i = 0; i < jfile_num - 1; i++) {
        //打开之前要切割的文件,以写入的方式打开文件
            FILE *patch = fopen(patchs[i],"wb");//若文件已经存在 就删除,只运行写
            for (int j = 0; j < patchSize; j++) {
                char ch = fgetc(fp);
                fputc(ch,patch);
            }
            fclose(patch);
        }

        FILE *patch = fopen(patchs[jfile_num-1],"wb");
        for (int i = 0; i < length % (jfile_num-1); i++) {
            char ch = fgetc(fp);
            fputc(ch,patch);
        }
        fclose(patch);
    }

    fclose(fp);
    for (int i = 0; i < jfile_num; ++i) {
        free(patchs[i]);
    }
    free(patchs);
    patchs =NULL;

    LOGE("文件切割完成");
    (*env)->ReleaseStringChars(env,jpath,path);
    (*env)->ReleaseStringChars(env,jpattern_path,pattern);
}


//文件合并
JNIEXPORT void JNICALL native_patch
        (JNIEnv *env, jclass clazz, jstring jpatchPath, jstring jpatternPath, jint jfile_num){
    LOGE("文件开始合并");
    char *patchPath = (*env)->GetStringUTFChars(env,jpatchPath,NULL);
    char *patternPath = (*env)->GetStringUTFChars(env,jpatternPath,NULL);

    //申请二维数组存放切割后的文件名字
    char** patchs = (char**)malloc(sizeof(char*)*jfile_num);
    //分配内存
    for(int i = 0;i<jfile_num;i++){
        patchs[i] = malloc(sizeof(char)*100);
        sprintf(patchs[i],patternPath,i);
        LOGE("每段文件的名字:%s",patchs[i]);
    }

    FILE *fp = fopen(patchPath,"wb");
    for(int i=0;i<jfile_num;i++){
        int patchLength = getFileLenth(patchs[i]);
        FILE *patch = fopen(patchs[i],"rb");
        for (int j = 0; j < patchLength; j++) {
            fputc(fgetc(patch),fp);
        }
        fclose(patch);
    }
    fclose(fp);

    for (int i = 0; i < jfile_num; ++i) {
        free(patchs[i]);
    }
    free(patchs);
    patchs =NULL;

    LOGE("文件合并完成");
    (*env)->ReleaseStringChars(env,jpatchPath,patchPath);
    (*env)->ReleaseStringChars(env,jpatternPath,patternPath);
}

//动态注册代码
static const JNINativeMethod gMethods[] = {
        {
                "diff","(Ljava/lang/String;Ljava/lang/String;I)V",(void*)native_diff
        },
        {
                "patch","(Ljava/lang/String;Ljava/lang/String;I)V",(void*)native_patch
        }
};

static int registerNatives(JNIEnv* engv)
{
    LOGE("registerNatives begin");
    jclass  clazz;
    clazz = (*engv) -> FindClass(engv, "com/cool/ndktest2/FileUtils");

    if (clazz == NULL) {
        LOGE("clazz is null");
        return JNI_FALSE;
    }

    if ((*engv) ->RegisterNatives(engv, clazz, gMethods, NELEM(gMethods)) < 0) {
        LOGE("RegisterNatives error");
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{

    LOGE("jni_OnLoad begin");

    JNIEnv* env = NULL;
    jint result = -1;

    if ((*vm)->GetEnv(vm,(void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed\n");
        return -1;
    }
    assert(env != NULL);

    registerNatives(env);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值