04.Eclipse下Ndk开发(以文件拆分合并为例模拟一下开发过程,参考文件加密的过程)

(创建于2017/12/6)

1.工具类PatchUtils

package com.ren.ndk_file_patch;

public class PatchUtils {
    
    static{
        System.loadLibrary("ndk_file_patch");
    }

    public native static void diff(String path,String path_pattern,int count);
    
    public native static void patch(String path_pattern,String merge_path,int count);
}

2.生成的头文件 com_ren_ndk_file_patch_PatchUtils.h

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

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

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

#ifdef __cplusplus
}
#endif
#endif

3.编写的c文件 ndk_file_patch.c

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

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

long get_file_size(const char *path){
    FILE *fl = fopen(path,"rb");
    //把与fp有关的文件位置指针放到一个指定位置。
    //文件指针定位到文件末尾,偏移0个字节 
    fseek(fl,0,SEEK_END);
    //函数用来获取文件读写指针的当前位置,对于二进制文件,则返回从文件开头到结尾的字节数。
    return ftell(fl);
}

JNIEXPORT void JNICALL Java_com_ren_ndk_1file_1patch_PatchUtils_diff
  (JNIEnv *env, jclass jclz, jstring path_jstr, jstring path_pattern_jstr, jint file_num){

    //转换文件路径
    const char *path = (*env)->GetStringUTFChars(env,path_jstr,NULL);
    const char *path_pattern = (*env)->GetStringUTFChars(env,path_pattern_jstr,NULL);

    //得到分割之后的所有文件路径

    //申请一段连续的内存空间(一个数组)保存所有分割的文件地址
    char **patches = malloc(sizeof(char*)*file_num);

    int i = 0;
    for(;i<file_num;i++){
        patches[i]=malloc(sizeof(char)*100);
        //元素赋值
        //需要分割的文件:C://jason/liuyan.png
        //子文件:C://jason/liuyan_%d.png(path_pattern的格式)
        sprintf(patches[i],path_pattern,(i+1));
        LOGI("patch path:%s",patches[i]);
    }
    //不断读取path文件,循环写入file_num个文件中
        //  整除
        //  文件大小:90,分成9个文件,每个文件10
        //  不整除
        //  文件大小:110,分成9个文件,
        //  前(9-1)个文件为(110/(9-1))=13
        //  最后一个文件(110%(9-1))=6

    //获取文件大小
    int file_size = get_file_size(path);
    //打开这个文件
    FILE *fpr = fopen(path,"rb");

    //整除
    if(file_size % file_num == 0){
        //单个文件大小
        int part = file_size/file_num;

        int i =0;
        //逐一写入设置好的子文件路径中
        for(;i<file_num;i++){
            //从子文件路径打开一个FILE
            FILE *fpw = fopen(patches[i],"wb");
            int j = 0;
            for(;j<part;j++){
                //边读边写
                //fgetc函数功能:从流中读取字符,即从fp所指定的文件中取得下一个字符。这里需要注意,在每取完一个字符时fp会自动向下移动一个字节。这样编成时,程序员就不用再对fp                 //控制了。这种功能在许多读写函数中都有体现。
                fputc(fgetc(fpr),fpw);
            }
            fclose(fpw);
        }
    }else{
        //无法整除
        int part = file_size/(file_num-1);
        int 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<file_size%(file_num-1);i++){
            fputc(fgetc(fpr),fpw);
        }
        fclose(fpw);
    }

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

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

/*
 * Class:     com_ren_ndk_file_patch_PatchUtils
 * Method:    patch
 * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
 */
JNIEXPORT void JNICALL Java_com_ren_ndk_1file_1patch_PatchUtils_patch
  (JNIEnv *env, jclass jclz, jstring path_pattern_jstr, jstring merge_path_jstr, jint file_num){
    //字符串转换
    const char *merge_path = (*env)->GetStringUTFChars(env,merge_path_jstr,NULL);
    const char *path_pattern = (*env)->GetStringUTFChars(env,path_pattern_jstr,NULL);
    //得到分割后的子文件路径列表
    char **patches = malloc(sizeof(char*)*file_num);
    int i = 0;
    for(;i<file_num;i++){
        patches[i]=malloc(sizeof(char)*100);
        //元素赋值
        //需要分割的文件:C://jason/liuyan.png
        //子文件:C://jason/liuyan_%d.png
        sprintf(patches[i],path_pattern,i+1);
        LOGI("patch path:%s",patches[i]);
    }
    //打开要merge_path为一个FILE
    FILE *fpw = fopen(merge_path,"wb");
    //把所有分割的文件读取一遍,写入到这个总的文件中
    i = 0;
    for(;i<file_num;i++){
        //得到每个子文件的大小
        int file_size = get_file_size(patches[i]);
        //打开每个子文件路径为一个FILE
        FILE *fpr = fopen(patches[i],"rb");
        int j =0;
        for(;j<file_size;j++){
            fputc(fgetc(fpr),fpw);
        }
        fclose(fpr);
    }
    fclose(fpw);

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

    (*env)->ReleaseStringUTFChars(env,merge_path_jstr,merge_path);
    (*env)->ReleaseStringUTFChars(env,path_pattern_jstr,path_pattern);
}

4.Android.mk文件

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := ndk_file_patch
LOCAL_SRC_FILES := ndk_file_patch.c
LOCAL_LDLIBS := -llog   //使用了log,需要引入

include $(BUILD_SHARED_LIBRARY)

5.开始拆分合并

public class MainActivity extends Activity {
    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 diff(View view){
        String path = SD_CARD_PATH +File.separatorChar+ "2.mp4";
        String path_pattern = SD_CARD_PATH +File.separatorChar+ "2_%d.mp4";
        PatchUtils.diff(path, path_pattern, 2);
        System.out.println("拆分完成");
    }
    public void patch(View view){
        String merge_path = SD_CARD_PATH +File.separatorChar+ "2_new.mp4";
        String path_pattern = SD_CARD_PATH +File.separatorChar+ "2_%d.mp4";
        PatchUtils.patch(path_pattern, merge_path, 2);
        System.out.println("合并完成");
    }
}

6.注意添加权限,6.0动态申请

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
上一篇:浅谈Orabbix监控指标


下一篇:在xcode中取得本机ip地址