原文網址:http://www.ithao123.cn/content-10709539.htmlhtml
使用NDK進行文件讀寫,有利於保存數據的安全性,項目須要,要文件讀寫從Java中處理搬到Linux平臺,爲了方便兩個平臺的代碼維護一致,使用JNI進行重寫編寫;java
public class MainActivity extends Activity implements OnClickListener { private String tag = getClass().getSimpleName(); private TextView textView; private static final String filePath = "/mnt/sdcard/hello.txt"; private int num = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView); findViewById(R.id.bt_add).setOnClickListener(this); findViewById(R.id.bt_del).setOnClickListener(this); findViewById(R.id.bt_update).setOnClickListener(this); findViewById(R.id.bt_select).setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_add: num++; JniFileTools.writeFile(filePath, ", "+num); textView.setText(JniFileTools.readFile(filePath)); break; case R.id.bt_del: JniFileTools.deleteString(filePath, ", "+num); textView.setText(JniFileTools.readFile(filePath)); if(num > 0){ num--; } break; case R.id.bt_update: break; case R.id.bt_select: textView.setText(JniFileTools.readFile(filePath)); break; default: break; } } }
JNI接口:android
package jni.file.tools; public class JniFileTools { private final static String tag = "JniFileTools"; static { System.loadLibrary("opfile"); } public final static native String readFile(String filePath); public final static native boolean writeFile(String filePath, String content); public final static native boolean deleteString(String filePath, String content); }
實現3個方法:c++
Java_jni_file_tools_JniFileTools_readFile();安全
Java_jni_file_tools_JniFileTools_writeFile();ide
Java_jni_file_tools_JniFileTools_deleteString();函數
JniFileTools.cppthis
#include <jni.h> #include"JniFileTools.h" #include<stdlib.h> #include<stdio.h> #include<android/log.h> #include <stdarg.h> void Log_i(const char* log, ...) { // 請引入#include <stdarg.h> va_list arg; va_start(arg, log); __android_log_vprint(ANDROID_LOG_INFO, "JniLogTools", log, arg); va_end(arg); } void readFromFile(char* fileName, char *str) { FILE *fp; int n = 0; char strTemp[128]; fp = fopen(fileName, "r"); if (fp == NULL) { Log_i("readFromFile打開失敗"); return; } while (NULL != fgets(strTemp, sizeof(strTemp), fp)) { strcat(str, strTemp); } fclose(fp); return; } unsigned char writeToFile(char* fileName, char* content, const char * mode) { FILE *fp; fp = fopen(fileName, mode); //w+ , "a+" if (fp == NULL) { fclose(fp); return false; } int length = strlen(content); for (int i = 0; i < length; i++) { fputc(content[i], fp); } fclose(fp); return true; } char * jstringToChar(JNIEnv *env, jstring jstr) { char * rtn = NULL; jclass clsstring = env->FindClass("java/lang/String"); jstring strencode = env->NewStringUTF("UTF-8"); jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode); jsize alen = env->GetArrayLength(barr); jbyte * ba = env->GetByteArrayElements(barr, JNI_FALSE); if (alen > 0) { rtn = (char*) malloc(alen + 1); //new char[alen+1]; memcpy(rtn, ba, alen); rtn[alen] = 0; } env->ReleaseByteArrayElements(barr, ba, 0); return rtn; } jstring charTojstring(JNIEnv* env, const char* pat) { jclass strClass = env->FindClass("Ljava/lang/String;"); jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V"); jbyteArray bytes = env->NewByteArray(strlen(pat)); env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*) pat); jstring encoding = env->NewStringUTF("utf-8"); return (jstring) env->NewObject(strClass, ctorID, bytes, encoding); } char *delSubstr(char *str, char *delstr) { char *p, *q; char *src, *dst; dst = src = str; while (*src != '\0') { p = src; q = delstr; while (*p == *q && *q != '\0') { p++; q++; } if (*q == '\0') { src = p; } else { *dst++ = *src++; } } *dst = '\0'; return str; } JNIEXPORT jstring JNICALL Java_jni_file_tools_JniFileTools_readFile( JNIEnv * env, jclass cls, jstring filePath) { char str[1024]; memset(str, 0, sizeof(str)); readFromFile(jstringToChar(env, filePath), str); return (env)->NewStringUTF(str); } JNIEXPORT jboolean JNICALL Java_jni_file_tools_JniFileTools_writeFile( JNIEnv * env, jclass cls, jstring filePath, jstring content) { writeToFile(jstringToChar(env, filePath), jstringToChar(env, content), "a+"); return true; } JNIEXPORT jboolean JNICALL Java_jni_file_tools_JniFileTools_deleteString( JNIEnv * env, jclass cls, jstring filePath, jstring content) { char str[1024]; memset(str, 0, sizeof(str)); readFromFile(jstringToChar(env, filePath), str); delSubstr(str,jstringToChar(env, content)); writeToFile(jstringToChar(env, filePath),str,"w+"); return true; }
Android.mk日誌
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libopfile LOCAL_SRC_FILES := \ JniFileTools.cpp LOCAL_LDLIBS :=-llog LOCAL_LDLIBS += -lGLESv2 -llog -ldl include $(BUILD_SHARED_LIBRARY)
注意使用權限:code
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
本案例中涉及到有:
1 delSubstr()刪除指定字符串;
2 jstring和char*之間的互相轉換;
3 讀寫模式a+和w+;
4 封裝輸出日誌到Logcat;
關於fopen()函數的幾個使用:
讀寫方式有下列幾種經常使用的形態:r 以只讀方式打開文件,該文件必須存在。r+ 以可讀寫方式打開文件,該文件必須存在。rb+ 讀寫打開一個二進制文件,容許讀寫數據,文件必須存在。w 打開只寫文件,若文件存在則文件長度清爲0,即該文件內容會消失。若文件不存在則創建該文件。w+ 打開可讀寫文件,若文件存在則文件長度清爲零,即該文件內容會消失。若文件不存在則創建該文件。a 以附加的方式打開只寫文件。若文件不存在,則會創建該文件,若是文件存在,寫入的數據會被加到文件尾,即文件原先的內容會被保留。(EOF符保留)a+ 以附加方式打開可讀寫的文件。若文件不存在,則會創建該文件,若是文件存在,寫入的數據會被加到文件尾後,即文件原先的內容會被保留。 (原來的EOF符不保留)