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
- 在拆分实现的时候,无论何种情况,得到的第最后一个拆分文件大小都为零,这里是因为在拆分的时候,大小的计算是基于字节大小的,故最后一个文件存储的大小是除数的字节数大小以下的一个值,很小。。。
NDK学习笔记-文件的拆分与合并的更多相关文章
- C#文件的拆分与合并操作示例
C#文件的拆分与合并操作示例代码. 全局变量定义 ;//文件大小 //拆分.合并的文件数 int count; FileInfo splitFile; string splitFliePath; Fi ...
- 《python基础教程(第二版)》学习笔记 文件和素材(第11章)
<python基础教程(第二版)>学习笔记 文件和素材(第11章) 打开文件:open(filename[,mode[,buffering]]) mode是读写文件的模式f=open(r' ...
- [Python学习笔记]文件的读取写入
文件与文件路径 路径合成 os.path.join() 在Windows上,路径中以倒斜杠作为文件夹之间的分隔符,Linux或OS X中则是正斜杠.如果想要程序正确运行于所有操作系统上,就必须要处理这 ...
- python学习笔记:文件操作和集合(转)
转自:http://www.nnzhp.cn/article/16/ 这篇博客来说一下python对文件的操作. 对文件的操作分三步: 1.打开文件获取文件的句柄,句柄就理解为这个文件 2.通过文件句 ...
- NDK学习笔记(四):OutputContext机制
首先NDK文档中的Op.h头文件中已经有了相关概念的解释,摘录翻译如下: /*! \fn const OutputContext& Op::outputContext() const; The ...
- NDK学习笔记(三):DynamicKnobs的机制
最近的NDK开发涉及到了动态input及动态knobs的问题. 开发需求如下:建立一个节点,该节点能获取每一个input上游的inputframerange信息. 具体下来就是:需要Node的inpu ...
- NDK学习笔记-增量更新
虽然现在有插件化开发和热修复,但为何还需要增量更新?插件化开发和热修复依赖于宿主程序,增量更新适合更新宿主程序. 差分包生成的前提 差分包的生成依赖于BsDiff开源项目,而BsDiff又依赖于Bzi ...
- .net学习笔记--文件读写的几种方式
在.net中有很多有用的类库来读写硬盘上的文件 一般比较常用的有: File:1.什么时候使用:当读写件大小不大,同时可以一次性进行读写操作的时候使用 2.不同的方式可以读写文件类型不 ...
- Python学习笔记——文件
1.文件只是连续的字节序列 open()内建函数是打开文件之门的钥匙 file_obj=open(file_name,access_mode='r/w/a,' buffering=-1) file_n ...
随机推荐
- 阿里云服务器(windows server 2012 r2 64位)安装MYSQL8.0.18数据库 (小白必备)
今儿中午询问了朋友关于服务器的一些事情后,就开始安装了,从中午大概一点,整到晚上九点,终于装成功了,感觉安装过程能遇到的问题全遇到了,给后面的朋友一些参考意见把. 第一次碰云服务器,措辞不当或不正确之 ...
- 2019HDU多校第四场 Just an Old Puzzle ——八数码有解条件
理论基础 轮换与对换 概念:把 $S$ 中的元素 $i_1$ 变成 $i_2$,$i_2$ 变成 $i_3$ ... $i_k$ 又变成 $i_1$,并使 $S$ 中的其余元素保持不变的置换称为循环, ...
- pycharm 头模板
#!/usr/local/bin/python3 # -*- coding: utf-8 -*- """ @author: Ray @contact: raylively ...
- 网络_05 STP HSRP
一.案例1:STP的基本配置 将S1配置成vlan1的主根,将S2配置成vlan2的次根 查看生成树的配置:show spanning-tree 查看某个vlan生成树的详细信息:show spann ...
- 洛谷P1903 [国家集训队]数颜色 / 维护队列 ( 带 修 )
题意:有两种操作: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col. 对每个1操作 输出答案: 带修莫队 模板题 (加 ...
- LOJ2537. 「PKUWC2018」Minimax [DP,线段树合并]
传送门 思路 首先有一个\(O(n^2)\)的简单DP:设\(dp_{x,w}\)为\(x\)的权值为\(w\)的概率. 假设\(w\)来自\(v1\)的子树,那么有 \[ dp_{x,w}=dp_{ ...
- Python流程控制和缩进
我们语文学写作文,有如果- -,那么- -的句式,同样Python也有这样的句式: #如何这个条件成立了,那就执行下面这个语句 if 条件: 内容1 内容2 else: 内容3 几点说明:
- fatal: unable to access 'https://github.com/Homebrew/brew/'
最近安装 Homebrew 遇到的坑,总结一下. 我的 Mac 版本是 10.13.6. 首先安装 Homebrew /usr/bin/ruby -e "$(curl -fsSL https ...
- Java并发指南3:并发三大问题与volatile关键字,CAS操作
本文转载自互联网,侵删 序言 先来看如下这个简单的Java类,该类中并没有使用任何的同步. 01 final class SetCheck { 02 private int a = 0; 03 ...
- Git 基本应用
微信公众号:Java修炼指南博客园:https://home.cnblogs.com/u/wuyx/CSDN: https://mp.csdn.net/简书:https://www.jianshu.c ...