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

文件拆分的思路

将文件大小拆分为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. 轮播图的3个常见bug,即处理bug思路及其解决办法

    1,下载jquery.js文件,并且导入 2,在下面的img中写入可以用图片路径 <!-- 第一个bug: 刚打开页面时,按一下左键图片没切换,再按第二下时才切换图片. 第二个bug: Ctrl ...

  2. Ubuntu 蓝牙鼠标的问题

    问题: 我有一个小巧的蓝牙鼠标,但有一个问题. 当它不使用一段时间时,它会关闭. 好的我得按按钮把它打开. 但是我发现,在我在蓝牙小程序下单击"连接"之前,它不会再被Ubuntu识 ...

  3. 编写测试类实现并发访问固定URL(亲测能用!!!)

    1.类目录 2.LatchTest.java类 package com.test; import java.util.concurrent.CountDownLatch; public class L ...

  4. ueditor自动上传Word中的图片

    如何做到 ueditor批量自动上传word图片? 1.前端引用代码 <!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//E ...

  5. C++泛型编程-扩展

    类型做参数是C++模板实现的主要形式.由此实现了类模板-->模板类-->实例的过程 当然除此之外也可以参考bitset的实现方式,参数决定类型的做法. #include <iostr ...

  6. luogu 2515

    对于软件的依赖可以转化为图上点之间的边的关系发现对于一个强联通分量内的软件,一安则全安Tarjan缩点缩点后,从虚拟节点 0 向所有入度为 0 的点连边这样就构成了一棵树树形 dp$dp[i][j]$ ...

  7. [Luogu] 【模板】点分治1

    // 模板题#include <bits/stdc++.h> ; , head[N], dis[N]; ]; int size[N], maxson[N], Root; bool vis[ ...

  8. 数据结构实验之栈与队列二:一般算术表达式转换成后缀式(SDUT 2132)

    题目链接 #include <bits/stdc++.h> using namespace std; typedef long long ll; int ok(char ch, char ...

  9. EGL Driver message (Critical) eglInitialize: No available renderers.

    使用Python的selenium库进行自动化巡检.并将相对应的数据保存 环境: Windows Embedded Standard Python 2.7.16 selenium 3.141.0 [0 ...

  10. 冲刺阶段——Day5

    [今日进展] 完成注册功能代码 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionLi ...