zoukankan      html  css  js  c++  java
  • NDK学习笔记-文件的拆分与合并

    文件的拆分与合并在开发中经常会用到,上传或是下载的时候都有这样的运用

    文件拆分的思路

    将文件大小拆分为n个文件
    那么,每个文件的大小就是等大小的
    如果文件大小被n除不尽,那么就使用n+1个文件来拆分
    最后一个文件的大小就是整除不尽的那一部分数据

    文件合并的思路

    将拆分出来的全部文件胺顺序读取
    挨个数据写入到指定文件中
    所有文件数据写入完毕
    那么合并就完成了

    代码实现

    布局文件(activity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="拆分"
            android:onClick="mDiff" />
        
        <Button 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="合并"
            android:onClick="mPatch"/>
    
    </LinearLayout>
    

    主活动文件(MainActivity.java

    import java.io.File;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Environment;
    import android.util.Log;
    import android.view.View;
    import android.widget.Toast;
    
    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 mDiff(View v) {
    		String path = SD_CARD_PATH + File.separatorChar + "test.mp3";
    		String path_pattern = SD_CARD_PATH + File.separatorChar + "test_%d.mp3";
    		Utils.diff(path, path_pattern, 3);
    		Toast.makeText(MainActivity.this, "···拆分完成···", Toast.LENGTH_SHORT).show();
    		Log.d("cj5785","···拆分完成···");
    	}
    	
    	public void mPatch(View v) {
    		String path_pattern = SD_CARD_PATH + File.separatorChar + "test_%d.mp3";
    		String path_merge = SD_CARD_PATH + File.separatorChar + "test_merge.mp3";
    		Utils.patch(path_pattern, path_merge, 3);
    		Toast.makeText(MainActivity.this, "···合并完成···", Toast.LENGTH_SHORT).show();
    		Log.d("cj5785","···合并完成···");
    	}
    }
    

    工具类文件(Utils.java

    public class Utils {
    
    	/**
    	 * 拆分
    	 * @param path 原始文件路径
    	 * @param path_pattern 拆分文件路径
    	 * @param count 拆分个数
    	 */
    	public native static void diff(String path, String path_pattern, int count);
    	
    	/**
    	 * 合并
    	 * @param path_pattern 拆分文件路径
    	 * @param path_merge 合并文件路径
    	 * @param count 拆分的文件个数
    	 */
    	public native static void patch(String path_pattern, String path_merge, int count);
    	
    	static {
    		System.loadLibrary("NdkFilePatch");
    	}
    	
    }
    

    JNI头文件(com_cj5785_ndkfilepatch_Utils.h

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_cj5785_ndkfilepatch_Utils */
    
    #ifndef _Included_com_cj5785_ndkfilepatch_Utils
    #define _Included_com_cj5785_ndkfilepatch_Utils
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_cj5785_ndkfilepatch_Utils
     * Method:    diff
     * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
     */
    JNIEXPORT void JNICALL Java_com_cj5785_ndkfilepatch_Utils_diff
      (JNIEnv *, jclass, jstring, jstring, jint);
    
    /*
     * Class:     com_cj5785_ndkfilepatch_Utils
     * Method:    patch
     * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
     */
    JNIEXPORT void JNICALL Java_com_cj5785_ndkfilepatch_Utils_patch
      (JNIEnv *, jclass, jstring, jstring, jint);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    JNI头文件实现(NdkFilePatch.c

    #include <stdlib.h>
    #include <stdio.h>
    #include <Android/log.h>
    
    #include "com_cj5785_ndkfilepatch_Utils.h"
    
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"cj5785",__VA_ARGS__)
    
    //获取文件大小
    long get_file_size(char const *path)
    {
    	FILE *fp = fopen(path,"rb");
    	fseek(fp,0,SEEK_END);
    	long size = ftell(fp);
    	fclose(fp);
    	return size;
    }
    
    //拆分
    JNIEXPORT void JNICALL Java_com_cj5785_ndkfilepatch_Utils_diff
      (JNIEnv *env, jclass jcls, 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 = (char **)malloc(sizeof(char *) * file_num);
    	memset(patches, 0, sizeof(char *) * file_num);
    	int i = 0;
    	for(;i < file_num;i++)
    	{
    		patches[i] = (char *)malloc(sizeof(char) * 100);
    		memset(patches[i], 0, sizeof(char) * 100);
    		//子文件名称
    		sprintf(patches[i], path_pattern, i+1);
    		LOGI("patch path:%s",patches[i]);
    	}
    
    	//读取path文件,写入到file_num个文件中
    	int file_size = get_file_size(path);
    	FILE *fpr = fopen(path, "rb");
    	//文件大小能被整除
    	if(file_size % file_num == 0)
    	{
    		int part = file_size / 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 = file_size / (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 < file_size % (file_num -1); i++)
    		{
    			fputc(fgetc(fpr),fpw);
    		}
    		fclose(fpw);
    	}
    	fclose(fpr);
    	//释放malloc的空间
    	i = 0;
    	for(;i < file_num; i++)
    	{
    		free(patches[i]);
    	}
    	free(patches);
    	patches = NULL;
    	//释放资源
    	(*env)->ReleaseStringUTFChars(env,path_jstr,path);
    	(*env)->ReleaseStringUTFChars(env,path_pattern_jstr,path_pattern);
    }
    
    //合并
    JNIEXPORT void JNICALL Java_com_cj5785_ndkfilepatch_Utils_patch
      (JNIEnv *env, jclass jcls, jstring path_pattern_jstr, jstring path_merge_jstr, jint file_num)
    {
    	//文件路径
    	const char *path_pattern = (*env)->GetStringUTFChars(env,path_pattern_jstr,NULL);
    	const char *path_merge = (*env)->GetStringUTFChars(env,path_merge_jstr,NULL);
    
    	//子文件路径列表
    	char **patches = (char **)malloc(sizeof(char *) * file_num);
    	memset(patches, 0, sizeof(char *) * file_num);
    	int i = 0;
    	for(; i < file_num; i++)
    	{
    		patches[i] = (char *)malloc(sizeof(char) * 100);
    		memset(patches[i], 0, sizeof(char) * 100);
    		sprintf(patches[i], path_pattern, i+1);
    		LOGI("patch path:%s", patches[i]);
    	}
    	FILE *fpw = fopen(path_merge, "wb");
    	i = 0;
    	for(; i < file_num; i++)
    	{
    		int file_size = get_file_size(patches[i]);
    		FILE *fpr = fopen(patches[i], "rb");
    		int j = 0;
    		for(; j < file_size; j++)
    		{
    			fputc(fgetc(fpr),fpw);
    		}
    		fclose(fpr);
    	}
    	fclose(fpw);
    	//释放malloc的空间
    	i = 0;
    	for(; i < file_num; i++)
    	{
    		free(patches[i]);
    	}
    	free(patches);
    	patches = NULL;
    	//释放资源
    	(*env)->ReleaseStringUTFChars(env,path_pattern_jstr,path_pattern);
    	(*env)->ReleaseStringUTFChars(env,path_merge_jstr,path_merge);
    }
    

    Android.mk文件

    因为在C实现代码中使用了日志打印,所以要在Android.mk文件中,添加日志打印的依赖

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE    := NdkFilePatch
    LOCAL_SRC_FILES := NdkFilePatch.c
    LOCAL_LDLIBS := -lm -llog
    
    include $(BUILD_SHARED_LIBRARY)
    

    问题总结

    • 在最开始的时候,日志无法打印,报错ANDROID_LOG_INFO不存在,添加本地支持以后仍然不行,无论怎么折腾,依旧如此。无奈之下,重启eclipse,居然好了。后经查阅得知,这是NDK r9d存在的bug,按照stackoverflow一位回答者的建议,先clean项目,然后build就好了:

    Cleaning the project and Project -> Build Project (I have Build Automatically disabled) recreated the .so library and all the symbols are now properly found

    • 在拆分实现的时候,无论何种情况,得到的第最后一个拆分文件大小都为零,这里是因为在拆分的时候,大小的计算是基于字节大小的,故最后一个文件存储的大小是除数的字节数大小以下的一个值,很小。。。
  • 相关阅读:
    redis持久化,主从及数据备份
    验证redis的快照和AOF
    Erlang中日志管理
    erlang tcp发包速度测试
    树(234树插入查找显示)
    JDBC(初步试用)
    树(二叉树的插入删除查找遍历)
    哈希表(链地址法插入删除)
    哈希表-再哈希法插入删除
    哈希表-线性探测插入删除
  • 原文地址:https://www.cnblogs.com/cj5785/p/10664671.html
Copyright © 2011-2022 走看看