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

    • 在拆分实现的时候,无论何种情况,得到的第最后一个拆分文件大小都为零,这里是因为在拆分的时候,大小的计算是基于字节大小的,故最后一个文件存储的大小是除数的字节数大小以下的一个值,很小。。。
  • 相关阅读:
    codeforces C. Fixing Typos 解题报告
    codeforces B. The Fibonacci Segment 解题报告
    codeforces B. Color the Fence 解题报告
    codeforces B. Petya and Staircases 解题报告
    codeforces A. Sereja and Bottles 解题报告
    codeforces B. Levko and Permutation 解题报告
    codeforces B.Fence 解题报告
    tmp
    API 设计 POSIX File API
    分布式跟踪的一个流行标准是OpenTracing API,该标准的一个流行实现是Jaeger项目。
  • 原文地址:https://www.cnblogs.com/cj5785/p/10664671.html
Copyright © 2011-2022 走看看