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 ...
随机推荐
- 8、Spring Boot 2.x 服务器部署
1.8 服务器部署 完整源码: Spring-Boot-Demos 1.8.1 jar包提取出来maven打包(避免每次重复打相同的jar包),pom.xml配置如下: <build> & ...
- P2215 [HAOI2007]上升序列 DP
这个字典序海星 思路:\(DP\) 提交:4次 错因:刚开始把字典序理解错了,怒看题解一脸懵逼:后来往前跳的时候又没有管上升\(QwQ\)窝太菜了. 题解: 所谓的字典序是相对位置!!!而不是元素本身 ...
- 003转载----C#打开网页
作者:微wx笑 来源:CSDN 原文:https://blog.csdn.net/testcs_dn/article/details/42246969 版权声明:本文为博主原创文章,转载请附上博文链接 ...
- InputStreamReader 和 FileReader联系与区别
两者关系: FileReader继承自InputStreamReader : 区别: InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字 ...
- STS创建spring boot项目,pom.xml文件第一行报错
亲测能用url地址:https://blog.csdn.net/jrx1995/article/details/100008552
- java实现文件夹上传
文件上传下载,与传统的方式不同,这里能够上传和下载10G以上的文件.而且支持断点续传. 通常情况下,我们在网站上面下载的时候都是单个文件下载,但是在实际的业务场景中,我们经常会遇到客户需要批量下载的场 ...
- 常用SQL之日期格式化和查询重复数据
本文列举一些工作中常用的SQL,以提升工作效率. 1 日期格式化 使用 DATE_FORMAT(get_date, '%Y-%m-%d') 函数进行格式化.其中:get_date 是需要被格式化的字段 ...
- 基于nodejs将mongodb的数据实时同步到elasticsearch
一.前言 因公司需要选用elasticsearch做全文检索,持久化存储选用的是mongodb,但是希望mongodb里面的数据发生改变可以实时同步到elasticsearch上,一开始主要使用ela ...
- Kafka - SASL认证
kafka SASL认证配置 1.找到kafka安装根目录,在config文件夹下创建kafka_server_jaas.conf,写入 KafkaServer { org.apache.kafka. ...
- np.random.choices的使用
在看莫烦python的RL源码时,他的DDPG记忆库Memory的实现是这样写的: class Memory(object): def __init__(self, capacity, dims): ...