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

文件拆分的思路

将文件大小拆分为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

  • 在拆分实现的时候,无论何种情况,得到的第最后一个拆分文件大小都为零,这里是因为在拆分的时候,大小的计算是基于字节大小的,故最后一个文件存储的大小是除数的字节数大小以下的一个值,很小。。。

NDK学习笔记-文件的拆分与合并的更多相关文章

  1. C#文件的拆分与合并操作示例

    C#文件的拆分与合并操作示例代码. 全局变量定义 ;//文件大小 //拆分.合并的文件数 int count; FileInfo splitFile; string splitFliePath; Fi ...

  2. 《python基础教程(第二版)》学习笔记 文件和素材(第11章)

    <python基础教程(第二版)>学习笔记 文件和素材(第11章) 打开文件:open(filename[,mode[,buffering]]) mode是读写文件的模式f=open(r' ...

  3. [Python学习笔记]文件的读取写入

    文件与文件路径 路径合成 os.path.join() 在Windows上,路径中以倒斜杠作为文件夹之间的分隔符,Linux或OS X中则是正斜杠.如果想要程序正确运行于所有操作系统上,就必须要处理这 ...

  4. python学习笔记:文件操作和集合(转)

    转自:http://www.nnzhp.cn/article/16/ 这篇博客来说一下python对文件的操作. 对文件的操作分三步: 1.打开文件获取文件的句柄,句柄就理解为这个文件 2.通过文件句 ...

  5. NDK学习笔记(四):OutputContext机制

    首先NDK文档中的Op.h头文件中已经有了相关概念的解释,摘录翻译如下: /*! \fn const OutputContext& Op::outputContext() const; The ...

  6. NDK学习笔记(三):DynamicKnobs的机制

    最近的NDK开发涉及到了动态input及动态knobs的问题. 开发需求如下:建立一个节点,该节点能获取每一个input上游的inputframerange信息. 具体下来就是:需要Node的inpu ...

  7. NDK学习笔记-增量更新

    虽然现在有插件化开发和热修复,但为何还需要增量更新?插件化开发和热修复依赖于宿主程序,增量更新适合更新宿主程序. 差分包生成的前提 差分包的生成依赖于BsDiff开源项目,而BsDiff又依赖于Bzi ...

  8. .net学习笔记--文件读写的几种方式

    在.net中有很多有用的类库来读写硬盘上的文件 一般比较常用的有: File:1.什么时候使用:当读写件大小不大,同时可以一次性进行读写操作的时候使用         2.不同的方式可以读写文件类型不 ...

  9. Python学习笔记——文件

    1.文件只是连续的字节序列 open()内建函数是打开文件之门的钥匙 file_obj=open(file_name,access_mode='r/w/a,' buffering=-1) file_n ...

随机推荐

  1. 2019HDU多校第四场 K-th Closest Distance ——主席树&&二分

    题意 给定 $n$ 个数,接下来有 $q$ 次询问,每个询问的 $l, r, p, k$ 要异或上一次的答案,才是真正的值(也就是强制在线).每次询问,输出 $[l, r]$ 内第 $k$ 小的 $| ...

  2. 008_STM32之_keil编译内存大小解析

    Program Size: Code=28784 RO-data=6480 RW-data=60 ZI-data=3900   的含义 1. Code: 程序所占用的FLASH大小,存储在FLASH. ...

  3. IDEA算法导包后 import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey;报错

    仔细查看报错原因就能知道,报错是因为包冲突的原因,可以每种只放一个jar包,就能过避免这种错误. 例如:只导入commons-codec-1.11-javadoc,jar和bcprov-jdk15on ...

  4. 面试题_Spring高级篇

    Spring高级篇 1.什么是 Spring 框架? Spring 框架有哪些主要模块?  Spring 框架是一个为 Java 应用程序的开发提供了综合.广泛的基础性支持的 Java 平台. Spr ...

  5. JavaWeb_(Mybatis框架)MyBatis整合Spring框架

    MyBatis + Spring整合开发 a)使用Spring容器用单例模式管理Mybatis的sqlSessionFactory:b)使用Spring管理连接池.数据源等:c)将Dao/Mapper ...

  6. Java学习日记——基础篇(一)常识

    JAVA简介 Java的标准 Java是一种语言,一个平台包含JavaSE.JavaEE.JavaME三个版本 JavaSE标准版(属于Java的基础部分,可以开发C/S构架的桌面应用程序) Java ...

  7. 多项式fft、ntt、fwt 总结

    做了四五天的专题,但是并没有刷下多少题.可能一开始就对多项式这块十分困扰,很多细节理解不深. 最简单的形式就是直接两个多项式相乘,也就是多项式卷积,式子是$N^2$的.多项式算法的过程就是把卷积做一种 ...

  8. Jmeter Web 性能测试入门 (五):Jmeter 参数化 Request

    用来参数化的常用方法: 添加配置元件:用户定义的变量 使用函数助手 添加配置元件:CSV Data Set Config 添加前置处理器:BeanShell PreProcessor 添加配置元件:用 ...

  9. 在Winform中屏蔽UnityWebPlayer的右键以及自带Logo解决方案整理

    根据项目的需要,对已经完成的Unity三维模型以及游戏要使用Winform进行包装,也就是使用Winform做一层外壳.因此在展示Unity的时候使用到了UnityWebPlayer这个插件,对于此插 ...

  10. 中国萌兔-月饼工厂流水线 -万圣节萌宠-月饼售罄后续-B站东予薏米

    B站(Blibli)up主,东予薏米.下面画的五只兔兔,两只狗狗,一只猫猫都是她家的 啊!有个会画画的主人真是幸福- 蹦迪的那个兔兔头昏脑胀,敷了冰袋和膏药哈哈哈哈,好可爱! 下班了下班了~今天真是太 ...