JNI 之 文件的拆分和合并

本文介绍如何通过Java调用C语言实现文件的拆分与合并功能,包括创建native方法、生成并调用so库的具体步骤,以及在Android平台上的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实现思路

创建native方法,然后生成so库,然后调用即可

二、实现

1、创建native方法

NDKFileUtils.java

public class NDKFileUtils {
    static {
        System.loadLibrary("native-lib");
    }

    /**
     * 文件的拆分
     * @param path 当前文件的地址
     * @param path_pattern 需要保存的路径
     * @param count 需要拆分的数量
     */
    public native static void diff(String path, String path_pattern, int count);

    /**
     * 文件的合并
     * @param merge_path 合并文件的路径
     * @param path_pattern 拆分的文件的路径
     * @param count 拆分的数量
     */
    public native static void patch(String merge_path,String path_pattern, int count);
}
2、调用native方法

MainActivity

public class MainActivity extends AppCompatActivity {
    private String sd_card_path;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sd_card_path= Environment.getExternalStorageDirectory().getAbsolutePath();
    }

    public void chaifen(View view) {

        String path = sd_card_path + File.separatorChar + "aaaa.mp4";
        String path_pattern = sd_card_path + File.separatorChar + "aaaa_%d.mp4";
        try {
            NDKFileUtils.diff(path,path_pattern,4);
        } catch (Throwable abloe) {
            Log.i("wanxiaofan", "error:"+abloe.getMessage());
        }
    }

    public void hebing(View view) {
        String path = sd_card_path + File.separatorChar + "aaaa_merge.mp4";
        String path_pattern = sd_card_path + File.separatorChar + "aaaa_%d.mp4";
        NDKFileUtils.patch(path,path_pattern,4);

    }


}

3、使用javah生成头文件

com_xiaofan_testndk2_NDKFileUtils.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_xiaofan_testndk2_NDKFileUtils */

#ifndef _Included_com_xiaofan_testndk2_NDKFileUtils
#define _Included_com_xiaofan_testndk2_NDKFileUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_xiaofan_testndk2_NDKFileUtils
 * Method:    diff
 * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
 */
JNIEXPORT void JNICALL Java_com_xiaofan_testndk2_NDKFileUtils_diff
  (JNIEnv *, jclass, jstring, jstring, jint);

/*
 * Class:     com_xiaofan_testndk2_NDKFileUtils
 * Method:    patch
 * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
 */
JNIEXPORT void JNICALL Java_com_xiaofan_testndk2_NDKFileUtils_patch
  (JNIEnv *, jclass, jstring, jstring, jint);

#ifdef __cplusplus
}
#endif
#endif

4、c文件实现头文件中的方法

native-lib.c

#include <jni.h>
#include "com_xiaofan_testndk2_NDKFileUtils.h"
#include <stdlib.h>
#include <stdio.h>
#include <android/log.h>

#define LOGI(FORMAT, ...)  __android_log_print(ANDROID_LOG_INFO,"wanxiaofan",FORMAT,__VA_ARGS__);
#define LOGE(FORMAT, ...)  __android_log_print(ANDROID_LOG_ERROR,"wanxiaofan",FORMAT,__VA_ARGS__);

//获取文件大小
long get_file_size(char *path) {
    FILE *fp = fopen(path, "rb");
    if (fp == NULL) {
        return 0;
    } else {
        fseek(fp, 0, SEEK_END);
        return ftell(fp);
    }
}

JNIEXPORT void JNICALL Java_com_xiaofan_testndk2_NDKFileUtils_diff
        (JNIEnv *env, jclass jcls, jstring path_jstr, jstring path_pattern_jstr, jint file_num) {
    //jstring->char*
    const char *path = (*env)->GetStringUTFChars(env, path_jstr, JNI_FALSE);
    const char *path_pattern = (*env)->GetStringUTFChars(env, path_pattern_jstr, JNI_FALSE);
    //得到分割之后的子文件的路径列表
    char **patches = malloc(sizeof(char *) * file_num);
    int i = 0;
    for (; i < file_num; i++) {
        patches[i] = malloc(sizeof(char) * 100);
        //元素赋值
        //D:aaa.mp4  ---> D:aaa_%d.mp4
        sprintf(patches[i], path_pattern, (i + 1));
        LOGI("patch path:%s", patches[i]);

    }

    //不断读取path文件,循环写入file_num个文件中
    int fileSize = get_file_size(path);

    LOGI("fileSize:%d", fileSize);

    FILE *fpr = fopen(path, "rb");
    if (fileSize != 0 && fpr != NULL) {
        if (fileSize % file_num == 0) {
            //能整除
            //单个文件大小
            int part = fileSize / file_num;
            i = 0;
            //逐一写入不同的分割子文件中
            for (; i < file_num; i++) {
                FILE *fpw = fopen(patches[i], "wb");
                int j = 0;
                for (; j < part; j++) {
                    //边读边写
                    fputc(fgetc(fpr), fpw);
                }
                fclose(fpw);
            }

        } else {
            //不整除
            int part = fileSize / (file_num - 1);

            i = 0;
            //逐一写入不同的分割子文件中
            for (; i < file_num - 1; i++) {
                FILE *fpw = fopen(patches[i], "wb");
                int j = 0;
                for (; j < part; j++) {
                    //边读边写
                    fputc(fgetc(fpr), fpw);
                }
                fclose(fpw);
            }
            //最后一个
            FILE *fpw = fopen(patches[file_num - 1], "wb");
            i = 0;
            for (; i < (fileSize % (file_num - 1)); i++) {
                fputc(fgetc(fpr), fpw);
            }
            fclose(fpw);
        }

    }
    //关闭被分割的文件
    fclose(fpr);
    //释放
    i = 0;
    for (; i < file_num; i++) {
        free(patches[i]);
    }
    free(patches);

    (*env)->ReleaseStringChars(env, path_jstr, path);
    (*env)->ReleaseStringChars(env, path_pattern_jstr, path_pattern);
}


JNIEXPORT void JNICALL Java_com_xiaofan_testndk2_NDKFileUtils_patch
        (JNIEnv * env, jclass jcls, jstring path_jstr, jstring path_pattern_jstr, jint count) {
    //合并之后的文件
    const char *merge_path = (*env)->GetStringUTFChars(env, path_jstr, JNI_FALSE);
    //被分割子文件的路径
    const char *pattern_path = (*env)->GetStringUTFChars(env, path_pattern_jstr, JNI_FALSE);

    //得到分割之后的子文件的路径列表
    char **patches = malloc(sizeof(char *) * count);
    int i = 0;
    for (; i < count; i++) {
        patches[i] = malloc(sizeof(char) * 100);
        //元素赋值
        //D:aaa.mp4  ---> D:aaa_%d.mp4
        sprintf(patches[i], pattern_path, (i + 1));
        LOGI("patch path:%s", patches[i]);
    }
    //把所有的分割文件读取一遍,写入一个总文件中
    i=0;
    FILE *fpw=fopen(merge_path,"wb");
    for (;i<count;i++){
        //每个子文件的大小
        int fileSize=get_file_size(patches[i]);
        FILE *fpr=fopen(patches[i],"rb");
        int j=0;
        for (; j <fileSize ; j++) {
            fputc(fgetc(fpr),fpw);
        }
        fclose(fpr);

    }

    fclose(fpw);

    //释放
    i = 0;
    for (; i < count; i++) {
        free(patches[i]);
    }
    free(patches);

    (*env)->ReleaseStringChars(env, path_jstr, merge_path);
    (*env)->ReleaseStringChars(env, path_pattern_jstr, pattern_path);
}

三、注意

不知道为什么在三星J5的手机获取不到文件的大小,也没有找到原因



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值