Android NDK 读写文件¶
更新日期 2021-9-1
- 2021-9-1 更新格式
- 2017-10-1 创建文档
旧文档
此文档比较旧,新的文档请参见NDK 读写文本文件
开发环境与工具: win7_x64,Android Studio 2.2.3, Cygwin
使用NDK,就进入了Linux的世界。理解了这一点,很多事情就好办了。需要熟悉C语言操作文件的方式。
准备事项¶
申请权限¶
申请SD卡的读写权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Android6.0开始需要动态申请权限。
使用文件绝对路径¶
手机sd卡中存放着文件。目录为 /sdcard/hello.txt
和/sdcard/egdir/csv/eg_data.csv
。
当然我们也可以在Java层获取文件路径后传入native方法。
读写示例¶
文件目录¶
Java文件¶
RWFile.java
里面写了多个native方法。
public class RWFile {
static {
System.loadLibrary("NDKMan");
}
public String readIn() {
return nativeRead();
}
public String writeToFile(String msg) {
return nativeWrite(msg);
}
public String readSDFile(String fileName) {
return nativeReadSDFile(fileName);
}
private native String nativeRead();
/**
* @param fileName e.g. FolderName/textFile.txt
*/
private native String nativeReadSDFile(String fileName);
private native String nativeWrite(String msg);
}
RWFile.c
编译出.h
文件后,里面的方法名。可以看出编译后的方法名和原来的native方法是一一对应的。
void join(char *s1, char *s2,char *result) // 拼接char的函数
Java_com_rustfisher_ndkalgo_RWFile_nativeRead // 读取固定文件的内容
Java_com_rustfisher_ndkalgo_RWFile_nativeReadSDFile // 根据文件名读取文件内容
Java_com_rustfisher_ndkalgo_RWFile_nativeWrite // 将内容写入文件
C文件¶
C文件是我们具体实现功能的地方。RWFile.c
代码如下。
#include <stdio.h>
#include <stdlib.h>
#include "com_rustfisher_ndkalgo_RWFile.h"
const char *sdcardDir = "/sdcard/";
void join(char *s1, char *s2,char *result) {
result = (char *) malloc(strlen(s1)+strlen(s2)+1);// +1 for the zero-terminator
if (result == NULL) {
return;
}
strcpy(result, s1);
strcat(result, s2);
}
JNIEXPORT jstring JNICALL Java_com_rustfisher_ndkalgo_RWFile_nativeRead
(JNIEnv *env, jobject jObj) {
FILE* file = fopen("/sdcard/hello.txt","r+");
char myStr[128];
if (file != NULL) {
char* readInPtr = fgets(myStr, 128, file);
fclose(file);
if (NULL != readInPtr) {
return (*env)->NewStringUTF(env, myStr);
}
return (*env)->NewStringUTF(env, "JNI read file fail!");
}
return (*env)->NewStringUTF(env, "JNI read file fail!");
}
JNIEXPORT jstring JNICALL Java_com_rustfisher_ndkalgo_RWFile_nativeReadSDFile
(JNIEnv *env, jobject jObj, jstring fileName) {
char *fileNamePtr = (*env)->GetStringUTFChars(env, fileName, 0);
char * result;
join(sdcardDir,fileNamePtr,result);
FILE* file = fopen(result,"r+");
if (file != NULL) {
char myStr[128];
char* readInPtr = fgets(myStr, 128, file);
fclose(file);
if (NULL != readInPtr) {
return (*env)->NewStringUTF(env, myStr);
}
return (*env)->NewStringUTF(env, "JNI read fail - NULL == readInPtr");
}
return (*env)->NewStringUTF(env, "JNI read file fail! - file is NULL ");
}
JNIEXPORT jstring JNICALL Java_com_rustfisher_ndkalgo_RWFile_nativeWrite
(JNIEnv *env, jobject jObj, jstring msg) {
FILE* file = fopen("/sdcard/hello.txt","w+");
const char *nativeMsg = (*env)->GetStringUTFChars(env, msg, 0);
if (file != NULL) {
fputs(nativeMsg, file);
fflush(file);
fclose(file);
}
return (*env)->NewStringUTF(env, "Write finished.");
}
需关注的函数¶
要特别关心函数的返回值,返回值往往代表着调用的结果。
打开文件 fopen
¶
FILE * fopen(const char * path,const char * mode);
mode模式选择,例如"r"
- r(read): 读
- w(write): 写
- a(append): 追加
- t(text): 文本文件,可省略不写
- b(banary): 二进制文件
- +: 读和写
凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。
用“w”打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已 经存在,则将该文件删去,重建一个新文件。这个方法保证目标文件里写入的只有我们要的数据。
若要向一个已存在的文件追加新的信息,只能用“a”方式打开文件。但此时该文件必须是存在的,否则将会出错。
在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成 打开文件的工作,并作相应的处理。
如果成功的打开一个文件, fopen()函数返回文件指针, 否则返回空指针
从文件中读取数据 fgets
¶
char *fgets(char *s, int n, FILE *stream);
从文件指针stream中读取n-1个字符,存到以s为起始地址的空间里,直到读完一行,如果成功则返回s的指
针,否则返回NULL。
NDK中生成jstring的函数 (*env)->NewStringUTF(env, char *);
¶
(*env)->NewStringUTF(env, char *);
如果传入的char*是一个空值,在一些平台上会报错。
比如红米手机会直接崩溃,而魅族手机能得到一个空的String。
可以参考NDK中的字符串
本站说明
一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。如有疑问和建议,欢迎在下方评论~