Android的NDK開發(5)————Android JNI層實現檔案的read、write與seek操作

來源:互聯網
上載者:User

/********************************************************************************************
 * author:conowen@大鐘                                                                                                                          
 * E-mail:conowen@hotmail.com                                                                                                             
 * http://blog.csdn.net/conowen                                                                                                              
 * 註:本文為原創,僅作為學習交流使用,轉載請標明作者及出處。     

 ********************************************************************************************/

1、

          在Android的java層實現檔案的讀寫操作是非常簡單的,可以參看之前寫的博文:http://blog.csdn.net/conowen/article/details/7296121

          在JNI層實現檔案的讀寫操作的話,就要使用到linux的讀寫函數了。

2、開啟檔案

int open( const char *pathname,int flags, int mode);

傳回值:為一個檔案控制代碼(fd),供read、write等操作。

參數:

pathname: 開啟的檔案所在路徑字串。如

String filename = "/sdcard/test.txt";

flags: 檔案開啟的方式

flag之間可以作“與”運算,如

open(filename, O_CREAT  | O_RDWR,mode);

常用flags
O_RDONLY 以唯讀方式開啟檔案
O_WRONLY 以唯寫方式開啟檔案
O_RDWR 以可讀寫方式開啟檔案。上述三種旗標是互斥的,也就是不可同時使用,但可與下列的旗標利用OR(|)運算子組合。
O_CREAT 若欲開啟的檔案不存在則自動建立該檔案。
O_TRUNC 若檔案存在並且以可寫的方式開啟時,此標誌位會令檔案長度重新清為0,也就是說檔案內容清空。
O_APPEND 當讀寫檔案時會從檔案尾開始移動,也就是所寫入的資料會以附加的方式加入到檔案後面。
O_NONBLOCK 以不可阻斷的方式開啟檔案,也就是無論有無資料讀取或等待,都會立即返回進程之中。
O_SYNC 以同步的方式開啟檔案。
O_NOFOLLOW 如果參數pathname所指的檔案為一符號串連,則會令開啟檔案失敗。
O_DIRECTORY 如果參數pathname所指的檔案並非為一目錄,則會令開啟檔案失敗。

mode: 檔案儲存體許可權

S_IRWXU00700 許可權,代表該檔案所有者具有可讀、可寫及可執行檔許可權。
S_IRUSR 或S_IREAD,00400許可權,代表該檔案所有者具有可讀取的許可權。
S_IWUSR 或S_IWRITE,00200 許可權,代表該檔案所有者具有可寫入的許可權。
S_IXUSR 或S_IEXEC,00100 許可權,代表該檔案所有者具有可執行檔許可權。
S_IRWXG 00070許可權,代表該檔案使用者組具有可讀、可寫及可執行檔許可權。
S_IRGRP 00040 許可權,代表該檔案使用者組具有可讀的許可權。
S_IWGRP 00020許可權,代表該檔案使用者組具有可寫入的許可權。
S_IXGRP 00010 許可權,代表該檔案使用者組具有可執行檔許可權。
S_IRWXO 00007許可權,代表其他使用者具有可讀、可寫及可執行檔許可權。
S_IROTH 00004 許可權,代表其他使用者具有可讀的許可權
S_IWOTH 00002許可權,代表其他使用者具有可寫入的許可權。
S_IXOTH 00001 許可權,代表其他使用者具有可執行檔許可權。

3、檔案的讀(read)操作

int read(int fd, unsigned char *buf, int size); 

傳回值:返回實際讀取到的位元組數,如果返回0,表示已到達檔案尾或是無可讀取的資料,此外檔案讀寫位置會隨讀取到的位元組移動。

參數:

fd:表示檔案控制代碼,是由open函數得到

buf:read()函數會把fd 所指的檔案傳送count個位元組到buf指標所指的記憶體中

size:要讀取的位元組數

4、寫入操作

 int write (int fd, const unsigned char *buf, int size); 

傳回值 :如果成功write(),就會返回實際寫入的位元組數。當有錯誤發生時則返回-1

參數:

fd:同上

buf:將要寫入到檔案裡面的內容。

size:要寫入的位元組數

5、跳轉操作

int64_t seek(int fd, int64_t pos, int whence)

傳回值:成功時則返回目前的讀寫位置,也就是距離檔案開頭多少個位元組,若有錯誤則返回-1。

參數:

fd:同上

pos:跳轉的相對量,可正可負,表示相對位置的前後關係

whence:跳轉的方向,whence取值如下所示

int SEEK_SET   =0;//將讀寫位置指向檔案頭後再增加offset個位移量。int SEEK_CUR   =1;//以目前的讀寫位置往後增加offset個位移量。int EEK_END    =2;//將讀寫位置指向檔案尾後再增加offset個位移量。

註:當size參數=0;whence = SEEK_END;時傳回值即為檔案大小。

6、關閉操作

int close(int fd)

7、簡單樣本




7.1、JNI代碼:(有JNI_onLoad函數)

//fs.c#include <unistd.h>#include <sys/stat.h>#include <sys/time.h>#include <stdlib.h>#include <fcntl.h> int file_open(const char *filename, int flags){int fd;      fd = open(filename, flags, 0666);    if (fd == -1)        return -1;    return fd;} int file_read(int fd, unsigned char *buf, int size){        return read(fd, buf, size);} int file_write(int fd, const unsigned char *buf, int size){        return write(fd, buf, size);} int64_t file_seek(int fd, int64_t pos, int whence){        if (whence == 0x10000) {        struct stat st;        int ret = fstat(fd, &st);        return ret < 0 ? -1 : st.st_size;    }    return lseek(fd, pos, whence);} int file_close(int fd){       return close(fd);}

//jni.c#define TAG "fs_jni"#include <android/log.h>#include "jniUtils.h"static const char* const kClassPathName = "com/conowen/fs/FsActivity";jintJava_com_conowen_fs_FsActivity_NativeFileOpen( JNIEnv* env, jobject thiz,jstring filename,jint flags ){    const char *filename_char = (*env)->GetStringUTFChars(env,filename, NULL); return file_open(filename_char, flags);}jintJava_com_conowen_fs_FsActivity_NativeFileRead(JNIEnv* env, jobject thiz,int fd,jbyteArray buf,jint size){unsigned char *buf_char = (char*)((*env)->GetByteArrayElements(env,buf, NULL));return file_read(fd, buf_char,  size);}jintJava_com_conowen_fs_FsActivity_NativeFileWrite(JNIEnv* env, jobject thiz,int fd,jbyteArray buf,jint size){unsigned char *buf_char = (char*)((*env)->GetByteArrayElements(env,buf, NULL));return file_write(fd, buf_char,  size);}jlongJava_com_conowen_fs_FsActivity_NativeFileSeek(JNIEnv* env, jobject thiz,int fd,jlong Offset,jint whence){return file_seek(fd, Offset,  whence);}jintJava_com_conowen_fs_FsActivity_NativeFileClose(JNIEnv* env, jobject thiz,int fd){return file_close(fd);}/******************************JNI registration.************************************/static JNINativeMethod gMethods[] = {    {"NativeFileOpen",       "(Ljava/lang/String;I)I",           (void *)Java_com_conowen_fs_FsActivity_NativeFileOpen},    {"NativeFileRead",    "(I[BI)I",        (void *)Java_com_conowen_fs_FsActivity_NativeFileRead},    {"NativeFileWrite",      "(I[BI)I",                          (void *)Java_com_conowen_fs_FsActivity_NativeFileWrite},    {"NativeFileSeek",       "(IJI)J",                           (void *)Java_com_conowen_fs_FsActivity_NativeFileSeek},    {"NativeFileClose",      "(I)I",                             (void *)Java_com_conowen_fs_FsActivity_NativeFileClose},};int register_com_conowen_fs_FsActivity(JNIEnv *env) {return jniRegisterNativeMethods(env, kClassPathName, gMethods, sizeof(gMethods) / sizeof(gMethods[0]));}

//jniUtils.h#ifndef _JNI_UTILS_H_#define _JNI_UTILS_H_#include <stdlib.h>#include <jni.h>#ifdef __cplusplusextern "C"{#endifint jniThrowException(JNIEnv* env, const char* className, const char* msg);JNIEnv* getJNIEnv();int jniRegisterNativeMethods(JNIEnv* env,                             const char* className,                             const JNINativeMethod* gMethods,                             int numMethods);#ifdef __cplusplus}#endif#endif /* _JNI_UTILS_H_ */

//onLoad.cpp#define TAG "fs_onLoad"#include <android/log.h>#include "jniUtils.h"extern "C" {extern int register_com_conowen_fs_FsActivity(JNIEnv *env);}static JavaVM *sVm;/* * Throw an exception with the specified class and an optional message. */int jniThrowException(JNIEnv* env, const char* className, const char* msg) {    jclass exceptionClass = env->FindClass(className);    if (exceptionClass == NULL) {        __android_log_print(ANDROID_LOG_ERROR,    TAG,    "Unable to find exception class %s",                    className);        return -1;    }    if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {        __android_log_print(ANDROID_LOG_ERROR,    TAG,    "Failed throwing '%s' '%s'",    className, msg);    }    return 0;}JNIEnv* getJNIEnv() {    JNIEnv* env = NULL;    if (sVm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {    __android_log_print(ANDROID_LOG_ERROR,TAG,"Failed to obtain JNIEnv");    return NULL;    }    return env;}/* * Register native JNI-callable methods. * * "className" looks like "java/lang/String". */int jniRegisterNativeMethods(JNIEnv* env,                             const char* className,                             const JNINativeMethod* gMethods,                             int numMethods){    jclass clazz;    __android_log_print(ANDROID_LOG_INFO, TAG, "Registering %s natives\n", className);    clazz = env->FindClass(className);    if (clazz == NULL) {        __android_log_print(ANDROID_LOG_ERROR, TAG, "Native registration unable to find class '%s'\n", className);        return -1;    }    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {        __android_log_print(ANDROID_LOG_ERROR, TAG, "RegisterNatives failed for '%s'\n", className);        return -1;    }    return 0;}//Dalvik虛擬機器載入C庫時,第一件事是調用JNI_OnLoad()函數jint JNI_OnLoad(JavaVM* vm, void* reserved) {    JNIEnv* env = NULL;    jint result = JNI_ERR;sVm = vm;    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {        __android_log_print(ANDROID_LOG_ERROR, TAG, "GetEnv failed!");        return result;    }    __android_log_print(ANDROID_LOG_INFO, TAG, "loading . . .");    if(register_com_conowen_fs_FsActivity(env) != JNI_OK) {    __android_log_print(ANDROID_LOG_ERROR, TAG, "can't load register_com_conowen_fs_FsActivity");        goto end;}    __android_log_print(ANDROID_LOG_INFO, TAG, "loaded");    result = JNI_VERSION_1_4;end:    return result;}

7.2、Android.mk檔案

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := fsLOCAL_SRC_FILES := fs.c jni.c onLoad.cppLOCAL_LDLIBS  += -lloginclude $(BUILD_SHARED_LIBRARY)

7.3、java層代碼

/* author:conowen * data:2012.5.1 * e-mail:conowen@hotmail.com */package com.conowen.fs;import java.io.UnsupportedEncodingException;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;public class FsActivity extends Activity {String filename = "/sdcard/test.txt";EditText writestrET;Button writeBT;Button readBT;Button seekBT;TextView readTV;String writeStr;byte[] buf_write;byte[] buf_read;int fd;int O_ACCMODE  =    0003;int O_RDONLY   =      00;int O_WRONLY   =      01;int O_RDWR     =      02;int O_CREAT    =    0100; /* not fcntl */int O_EXCL     =    0200; /* not fcntl */int O_NOCTTY   =   0400; /* not fcntl */int O_TRUNC    =   01000; /* not fcntl */int O_APPEND   =   02000;int O_NONBLOCK =   04000;int O_NDELAY   = O_NONBLOCK;int O_SYNC     =  010000;int O_FSYNC    =  O_SYNC;int O_ASYNC    =  020000;int SEEK_SET   =0;//將讀寫位置指向檔案頭後再增加offset個位移量。int SEEK_CUR   =1;//以目前的讀寫位置往後增加offset個位移量。int EEK_END    =2;//將讀寫位置指向檔案尾後再增加offset個位移量。 /** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);writestrET = (EditText) findViewById(R.id.writeET);writeBT = (Button) findViewById(R.id.writeBT);readBT = (Button) findViewById(R.id.readBT);seekBT = (Button) findViewById(R.id.seekBT);readTV = (TextView) findViewById(R.id.readTV);writeBT.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubfd = NativeFileOpen(filename, O_CREAT  | O_RDWR);System.out.println("fd_write---->" + fd);writeStr = writestrET.getText().toString();buf_write = writeStr.getBytes();int ret_write = NativeFileWrite(fd, buf_write, buf_write.length);System.out.println("寫入返回結果" + ret_write);NativeFileClose(fd);}});readBT.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubfd = NativeFileOpen(filename, O_CREAT  | O_RDWR);System.out.println("fd_read---->" + fd);buf_read = new byte[buf_write.length];int ret_read = NativeFileRead(fd, buf_read, buf_write.length);System.out.println("讀出返回結果" + ret_read);try {readTV.setText( new String(buf_read, "GB2312") + "");} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}NativeFileClose(fd);}});seekBT.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubfd = NativeFileOpen(filename, O_CREAT  | O_RDWR);long Offset=20;long ret_seek =NativeFileSeek(fd, Offset, SEEK_CUR);System.out.println("seek返回結果" + ret_seek);NativeFileClose(fd);/*    1) 欲將讀寫位置移到檔案開頭時:  lseek(int fildes,0,SEEK_SET);  2) 欲將讀寫位置移到檔案尾時:  lseek(int fildes,0,SEEK_END);  3) 想要取得目前檔案位置時:  lseek(int fildes,0,SEEK_CUR);傳回值:當調用成功時則返回目前的讀寫位置,也就是距離檔案開頭多少個位元組。若有錯誤則返回-1,errno 會存放錯誤碼。 * */}});}public native int NativeFileOpen(String filename, int flags);public native int NativeFileRead(int fd, byte[] buf, int sizes);public native int NativeFileWrite(int fd, byte[] buf, int sizes);public native long NativeFileSeek(int fd, long Offset, int whence);//Offset:位移量,每一讀寫操作所需要移動的距離,單位是位元組的數量,可正可負(向前移,向後移)。public native int NativeFileClose(int fd);static {System.loadLibrary("fs");}}

最後記得在manifest.xml裡面加上SD卡操作許可權

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.