02.文件的拆分和合并

前提

这次是将大文件拆分成多分小文件,比如将一个3m的test.mp3文件,分割成3个小的为1m的test_1.mp3,test3.mp_2,test_3.mp3。使用场景为,上传至服务器,如果一次上传很大的文件可能会非常慢,而且如果在上传过程中进程中断可能会导致需要重写上传。我们可以在上传过程中先将大文件分割成小文件再上传可能要好一些。本人没有什么正在的开发经验只是学习了这种分割方法而已。

1.native方法

package com.gxl.patch;

public class PatchUtil {

    /**
     * 分割文件
     * @param fiePath 被分割的文件
     * @param count 要分割的数量
     * @param segmentPath 分割后的路径
     */
    public native void segmen(String fiePath,int count,String segmentPath);

    /**
     * 分割文件
     * @param fiePath 分割文件的路径
     * @param count 分割文件的数量
     * @param segmentPath 合并后的路径
     */
    public native void merge(String segmentPath,int count,String mergePath);

    static {
        System.loadLibrary("patch");
    }
}

2.函数的实现

对应ndk对应的开发流程,参考上一篇,最后会到patch.c中进行函数实现

#include "com_gxl_patch_PatchUtil.h"
#include <stdlib.h>
#include <stdio.h>

//日记
#include <android/log.h>
#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"gxl",FORMAT,__VA_ARGS__)
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"gxl",FORMAT,__VA_ARGS__)

//获取文件大小
long getFileSize(char* fiel_path) {
    //将file_path转成File
    FILE* file = fopen(fiel_path, "rb");
    fseek(file, 0, SEEK_END);
    return ftell(file);
}

//分割文件
JNIEXPORT void JNICALL Java_com_gxl_patch_PatchUtil_segmen(JNIEnv * env,
        jobject jobj, jstring file_path_str, jint count,
        jstring segmen_path_str) {
    //将jstrin转成char*
    //获取要要分割文件地址,和分割后文件地址
    const char* file_path = (*env)->GetStringUTFChars(env, file_path_str,
            JNI_FALSE);
    const char* segmen_path = (*env)->GetStringUTFChars(env, segmen_path_str,
            JNI_FALSE);

    //获取分割文件后子文件的路径
    //给分割文件路径数组开辟内存
    //得到分割之后的子文件的路径列表
    char** patchs = malloc(sizeof(char*) * count);
    int i = 0;
    for (; i < count; i++) {
        //元素赋值
        //需要分割的文件:C://jason/liuyan.png
        //子文件:C://jason/liuyan_%d.png
        //sprintf()函数用于将格式化的数据写入字符串
        //三个参数:tr为要写入的字符串;format为格式化字符串,与printf()函数相同;argument为变量
        //给每一个路径分配内存
        patchs[i] = malloc(sizeof(char) * 100);
        //给每一个路径赋值
        sprintf(patchs[i], segmen_path, (i + 1));
        //打印日志,这里有点打印不出
        LOGI("patch: %s", patchs[i]);
    }

    //获取被分割文件大小
    int fileSize = getFileSize(file_path);
    //被分割文文件
    FILE* file = fopen(file_path, "rb");

    //不断读取path文件,循环写入file_num个文件中
    //    整除
    //        文件大小:90,分成3个文件,每个文件30
    //    不整除
    //         如果是100 分成3份
    //         100/3=33;
    //         前count-1为33
    //        最后一个为 100-33(count-1)=34

    //如果文件大小刚好可以分成count个文件
    if (fileSize % count == 0) {
        //被拆分的单个文件大小
        int part = fileSize / count;
        //不断读取path文件,循环写入file_num个文件中
        i = 0;
        for (; i < count; i++) {
            //要分割的path的file
            FILE* patch = fopen(patchs[i], "wb");
            //不断的循环读取patch,
            int j = 0;
            for (; j < part; j++) {
                //逐一写入不同的分割子文件中
                fputc(getc(file), patch);
            }
            fclose(patch);
        }
    } else {
        //单个文件大小
        int part = fileSize / count;
        //对应前count-1个文件
        i = 0;
        for (; i < count - 1; i++) {
            //要分割的path的file
            FILE* patch = fopen(patchs[i], "wb");
            //不断的循环读取patch,
            int j = 0;
            for (; j < part; j++) {
                fputc(getc(file), patch);
            }
            fclose(patch);
        }
        //最后一个文件
        FILE* last_patch = fopen(patchs[count - 1], "wb");
        int lastSize = fileSize - (count - 1) * part;
        i = 0;
        for (; i < lastSize; i++) {
            fputc(getc(file), last_patch);
        }
        fclose(last_patch);
    }

    //释放
    fclose(file);

    i = 0;
    for (; i < count; i++) {
        free(patchs[i]);
    }
    free(patchs);

    (*env)->ReleaseStringUTFChars(env, file_path_str, file_path);
    (*env)->ReleaseStringUTFChars(env, segmen_path_str, segmen_path);
}

//合并文件
JNIEXPORT void JNICALL Java_com_gxl_patch_PatchUtil_merge(JNIEnv * env,
        jobject jobj, jstring segmen_path_str, jint count,
        jstring merge_path_str) {
    //将jstrin转成char*
    //获取要要分割文件地址,和分割后文件地址
    const char* segmen_path = (*env)->GetStringUTFChars(env, segmen_path_str,
            JNI_FALSE);
    const char* merge_path = (*env)->GetStringUTFChars(env, merge_path_str,
            JNI_FALSE);
    //分割文件的路径
    char** patchs = malloc(sizeof(char*) * count);
    int i = 0;
    for (; i < count; i++) {
        //元素赋值
        //需要分割的文件:C://jason/liuyan.png
        //子文件:C://jason/liuyan_%d.png
        //sprintf()函数用于将格式化的数据写入字符串
        //三个参数:tr为要写入的字符串;format为格式化字符串,与printf()函数相同;argument为变量
        //给每一个路径分配内存
        patchs[i] = malloc(sizeof(char) * 100);
        //给每一个路径赋值
        sprintf(patchs[i], segmen_path, (i + 1));
    }
    //合并文件
    FILE* merge_file=fopen(merge_path,"wb");

    i=0;
    for(;i<count;i++){
        //分割文件
        FILE* segmen_file=fopen(patchs[i],"rb");
        //获取分割文件的大小
        int segme_file_size=getFileSize(patchs[i]);
        //不断读写将文件写入到合并文件中
        int j=0;
        for(;j<segme_file_size;j++){
            fputc(fgetc(segmen_file),merge_file);
        }
        fclose(segmen_file);
    }

    //释放
    fclose(merge_file);

    i = 0;
    for (; i < count; i++) {
        free(patchs[i]);
    }
    free(patchs);

    (*env)->ReleaseStringUTFChars(env, segmen_path_str, segmen_path);
    (*env)->ReleaseStringUTFChars(env, merge_path_str, merge_path);
}

猜你喜欢

转载自blog.csdn.net/a_thousand_miles/article/details/81127645