轉載請以連接形式標明出處: 本文出自:103style的博客android
本文操做以 Android Studio 3.4.2 版本爲例git
NDK開發文章彙總github
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
複製代碼
JniFileOperation
類,編寫對應的測試代碼:public class JniFileOperation {
private static final String TAG = "JniFileOperation";
static {
System.loadLibrary("file_operation");
}
/**
* 原文件名
*/
private String fileName = "split_test.txt";
/**
* 合併拆分以後文件的文件名
*/
private String mergeFileName = "split_test_merged.txt";
/**
* 文件拆分格式
*/
private String splitFileFormat = "split_test_%d.txt";
/**
* 拆分的數量
*/
private int splitCount = 4;
public native void createFile(String fileName);
/**
* 拆分
*
* @param path 文件路徑
* @param pathPattern 拆分以後文件的路徑格式
* @param splitCount 拆分紅幾個
*/
public native void split(String path, String pathPattern, int splitCount);
/**
* 合併
*
* @param pathMerge 合併以後的文件路徑
* @param pathPattern 要合併的文件的路徑格式
* @param count 要合併的文件數量
*/
public native void merge(String pathMerge, String pathPattern, int count);
/**
* 測試文件 拆分與合併
*/
public void test() {
String filePath = Config.getBaseUrl() + fileName;
Log.e(TAG, "filePath = " + filePath);
File file = new File(filePath);
if (!file.exists()) {
Log.e(TAG, "開始建立文件");
createFile(filePath);
}
String pathPattern = Config.getBaseUrl() + splitFileFormat;
split(filePath, pathPattern, splitCount);
Log.e(TAG, "文件拆分紅功");
String mergePath = Config.getBaseUrl() + mergeFileName;
merge(mergePath, pathPattern, splitCount);
Log.e(TAG, "文件合併成功");
}
}
複製代碼
file_operation.cpp
CMakeLists.txt
:add_library(
file_operation
SHARED
file_operation.cpp)
target_link_libraries(
file_operation
${log-lib})
複製代碼
#include <jni.h>
#include <cstdio>
#include <cstdlib>
#include <android/log.h>
#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"com_lxk_ndkdemo",FORMAT,##__VA_ARGS__);
const int SIZE = 100;
/**
* 建立拆分原文件
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_lxk_ndkdemo_JniFileOperation_createFile(JNIEnv *env, jobject instance, jstring fileName_) {
const char *fileName = env->GetStringUTFChars(fileName_, nullptr);
//建立寫文件流
FILE *fp = fopen(fileName, "wb");
//寫文件
for (int i = 0; i < SIZE; i++) {
fputs("0123456789\n", fp);
}
//關閉流
fclose(fp);
LOGE("%s", "建立文件成功");
env->ReleaseStringUTFChars(fileName_, fileName);
}
複製代碼
/**
* 根據文件的路徑,得到文件的大小
*/
long get_file_size(const char *path) {
//rb:只讀打開一個二進制文件,容許讀數據
//使用給定的模式 "rb" 打開 path 所指向的文件
FILE *fp = fopen(path, "rb");
if (fp == nullptr) {
LOGE("%s", "文件打開失敗");
return 0;
}
//SEEK_SET 文件的開頭
//SEEK_CUR 文件指針的當前位置
//SEEK_END 文件的末尾
//設置流 fp 的文件位置爲 0, 0 意味着從給定的 SEEK_END 位置查找的字節數。
fseek(fp, 0, SEEK_END);
//返回給定流 fp 的當前文件位置。
return ftell(fp);
}
/**
* 拆分文件
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_lxk_ndkdemo_JniFileOperation_split(JNIEnv *env, jobject instance, jstring path_,
jstring pathPattern_, jint splitCount) {
const char *path = env->GetStringUTFChars(path_, nullptr);
const char *pathPattern = env->GetStringUTFChars(pathPattern_, nullptr);
//malloc:分配所需的內存空間,並返回一個指向它的指針。
char **patches = new char *[splitCount];
//獲取文件長度
long fileSize = get_file_size(path);
//獲取單個文件長度
long per_size = fileSize / splitCount;
//設置每一個子文件的路徑
for (int i = 0; i < splitCount; i++) {
patches[i] = new char[256];
sprintf(patches[i], pathPattern, i);
LOGE("patches[%d] = %s", i, patches[i]);
}
//建立fp流讀取path對應的文件
FILE *fp = fopen(path, "rb");
if (fp == nullptr) {
LOGE("%s", "文件打開失敗");
return;
}
//讀取分割文件的流
FILE *index_fp = nullptr;
int index = 0;
for (int i = 0; i < fileSize; i++) {
if (i % per_size == 0) {
if (index_fp != nullptr) {
fclose(index_fp);
}
index_fp = fopen(patches[index], "wb");
index++;
if (index_fp == nullptr) {
LOGE("文件%s打開失敗", patches[index]);
return;
}
}
fputc(fgetc(fp), index_fp);
//讀完以後釋放流
if (i + 1 == fileSize) {
fclose(index_fp);
}
}
fclose(fp);
//釋放內存
for (int i = 0; i < splitCount; i++) {
free(patches[i]);
}
free(patches);
env->ReleaseStringUTFChars(path_, path);
env->ReleaseStringUTFChars(pathPattern_, pathPattern);
}
複製代碼
/**
* 合併拆分文件
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_lxk_ndkdemo_JniFileOperation_merge(JNIEnv *env, jobject instance, jstring pathMerge_,
jstring pathPattern_, jint count) {
const char *pathMerge = env->GetStringUTFChars(pathMerge_, nullptr);
const char *pathPattern = env->GetStringUTFChars(pathPattern_, nullptr);
//建立合併文件的寫流
FILE *fp = fopen(pathMerge, "wb");
for (int i = 0; i < count; i++) {
char *index = new char[256];
sprintf(index, pathPattern, i);
//讀取每一個分割文件
FILE *index_fp = fopen(index, "rb");
if (index_fp == nullptr) {
LOGE("文件%s讀取失敗", index)
return;
}
//依次寫入合併文件
int ch;
while ((ch = fgetc(index_fp)) != EOF) {
fputc(ch, fp);
}
//關閉當前的分割文件流
fclose(index_fp);
//釋放拆分文件名的內存
free(index);
}
fclose(fp);
env->ReleaseStringUTFChars(pathMerge_, pathMerge);
env->ReleaseStringUTFChars(pathPattern_, pathPattern);
}
複製代碼
private void testFileOperation() {
if (hasFilePermission()) {
new JniFileOperation().test();
Toast.makeText(this, "任務完成,測試文件路徑:" + Config.getBaseUrl(), Toast.LENGTH_SHORT).show();
}
}
複製代碼
會在/storage/emulated/0/NDKDemo/
下生成對應的測試文件。bash
Demo地址:https://github.com/103style/NDKDoc/tree/master/NDKDemo測試
若是以爲不錯的話,請幫忙點個讚唄。ui
以上this
掃描下面的二維碼,關注個人公衆號 Android1024, 點關注,不迷路。 spa