NDK开发之JNI基础(3),文件拆分与合并

概述

之前描述了一些JNI的基础还有静态注册和动态注册,现在则通过一个简单的demo来总结一些JNI开发时的基本流程

文件拆分和合并

  1. 首先新建一个包含ndk项目,当然也可以不包含ndk,后续通过手动添加配置即可
    如果创建的文件不包含ndk,那么需要手动添加(添加方式)
    并且在CMakeList.txt文件中进行配置
#这是cmake版本信息
cmake_minimum_required(VERSION 3.4.1)
# 这是编译后的so库和cpp文件路径
add_library( # Sets the name of the library.
             #编译后的so库文件名
             native-lib
             #动态库类型,一般用SHARED
             # Sets the library as a shared library.
             SHARED
            #cpp文件路径
             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )

#导入的系统库,这里导入log库用于日志输出
find_library( # Sets the name of the path variable.
              log-lib
              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

#链接系统的log库到我们的native-lib库
target_link_libraries( # Specifies the target library.
                       native-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

这样一个简单的CMakeList文件就编写好了,当然CMakeList语法不仅仅这些,后续有机会再继续

  1. 定义拆分和合并的方法
//拆分
external fun split(inputPath: String, outputPath: String, number: Int)
//合并
external fun merge(inputPath: String, outputPath: String, number: Int)

3.1. 实现native方法
首先导入基础库,并且定义日志打印方法

#include 
#include 
#include 
#include 
#include 

#define TAG "tianyl"
#define LOGI(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)

3.2. 然后定义工具的方法

//获取文件大小
long getFileSize(const char *path) {
    LOGI("fopen path %s", path);
    FILE *fp = fopen(path, "rb");
    if (fp == NULL) {
        LOGI("fopen error %d\n", errno);
        return 0;
    }
    fseek(fp, 0, SEEK_END);
    long ret = ftell(fp);
    fclose(fp);
    return ret;
}

3.3. 实现拆分方法

extern "C" JNIEXPORT void JNICALL
Java_com_demo_tianyl_jnidemo_MainActivity_split(
        JNIEnv *env, jobject /* this */, jstring inputPath, jstring outputPath, jint fileNum) {
    LOGI("java的String转换成c的string");
    //java的String转换成c的string
    const char *inputPathStr = env->GetStringUTFChars(inputPath, NULL);
    const char *outputPathStr = env->GetStringUTFChars(outputPath, NULL);
    LOGI("申请字符数组, 存放子文件名");
    //申请字符数组, 存放子文件名
    char **paths = (char **) malloc(sizeof(char *) * fileNum);
    LOGI("每个文件名申请地址 char = %d char * = %d", sizeof(char), sizeof(char *));
    int i = 0;
    for (; i < fileNum; i++) {
        //每个文件名申请地址
        //每个文件名申请地址
        paths[i] = (char *) malloc(sizeof(char) * 100);
        // 需要分割的文件 xxx
        // 每个子文件名称 xxx_n
        sprintf(paths[i], outputPathStr, i);// 格式化文件名,给拆分后的加后缀
    }
    LOGI("准备拆分");
    int fileSize = getFileSize(inputPathStr);
    if (fileSize == 0) {
        free(paths);
        env->ReleaseStringUTFChars(inputPath, inputPathStr);
        env->ReleaseStringUTFChars(outputPath, outputPathStr);
        LOGI("文件拆分失败 1");
        return;
    }
    FILE *fpr = fopen(inputPathStr, "rb");
    LOGI("开始拆分");
    /*
     * 1.判断文件大小能够被 fileNum整除
     * 2.能整除就平分
     * 3.不能整除就先分 fileNum -1 ,剩下的给最后一个
     * */
    if (fileSize % fileNum == 0) {
        int part = fileSize / fileNum;
        for (int i = 0; i < fileNum; i++) {
            FILE *fpw = fopen(paths[i], "wb");//文件已经存在 就删除,只运行写
            for (int j = 0; j < part; j++) {
                fputc(fgetc(fpr), fpw);
            }
            fclose(fpw);
        }
    } else {
        int part = fileSize / (fileNum - 1);
        for (int i = 0; i < fileNum - 1; i++) {
            FILE *fpw = fopen(paths[i], "wb");//文件已经存在 就删除,只运行写
            for (int j = 0; j < part; j++) {
                fputc(fgetc(fpr), fpw);
            }
            fclose(fpw);
        }

        FILE *fpw = fopen(paths[fileNum - 1], "wb");
        for (int i = 0; i < fileSize % (fileNum - 1); i++) {
            fputc(fgetc(fpr), fpw);
        }
        fclose(fpw);
    }
    LOGI("拆分结束");
    fclose(fpr);

    for (int i = 0; i < fileNum; i++) {
        free(paths[i]);
    }
    free(paths);
    env->ReleaseStringUTFChars(inputPath, inputPathStr);
    env->ReleaseStringUTFChars(outputPath, outputPathStr);
    LOGI("拆分return");
    return;
}

3.4. 实现合并方法

extern "C" JNIEXPORT void JNICALL
Java_com_demo_tianyl_jnidemo_MainActivity_merge
        (JNIEnv *env, jobject /* this */, jstring inputPath, jstring outputPath, jint fileNum)
{
    LOGI("java的String转换成c的string");
    //java的String转换成c的string
    const char *inputPathStr = env->GetStringUTFChars(inputPath, NULL);
    const char *outputPathStr = env->GetStringUTFChars(outputPath, NULL);
    LOGI("申请字符数组, 存放子文件名");
    //申请字符数组, 存放子文件名
    char **paths = (char **) malloc(sizeof(char *) * fileNum);

    int i = 0;
    for (; i < fileNum; i++) {
        //每个文件名申请地址
        //每个文件名申请地址
        paths[i] = (char *) malloc(sizeof(char) * 100);
        // 需要合并的文件 xxx
        // 每个子文件名称 xxx_n
        sprintf(paths[i], outputPathStr, i);// 格式化文件名
    }

    FILE *fpw = fopen(outputPathStr, "wb");

    for (int i =0; i < fileNum; i++) {
        int fileSize = getFileSize(paths[i]);
        FILE *fpr = fopen(paths[i], "rb");
        for (int j =0; j < fileSize; j++) {
            fputc(fgetc(fpr), fpw);
        }
        fclose(fpr);
    }
    fclose(fpw);

    for (int i =0; i< fileNum; i++) {
        free(paths[i]); //每一个malloc 对应一个free
    }
    free(paths);
    env->ReleaseStringUTFChars(inputPath, inputPathStr);
    env->ReleaseStringUTFChars(outputPath, outputPathStr);
    LOGI("合并结束return");
}

以上,一个简单的JniDemo就完成了,当然,最后别忘记了添加权限,并且在系统中允许,大坑,切记!



项目Git地址

你可能感兴趣的:(NDK开发之JNI基础(3),文件拆分与合并)