分享

Android的NDK开发(5)————Android JNI层实现文件的read、wri...

 mandrave 2013-04-13

/********************************************************************************************
 * 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、打开文件

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

返回值:为一个文件句柄(fd),供read、write等操作。


参数:

pathname: 打开的文件所在路径字符串。如

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

flags: 文件打开的方式

flag之间可以作“与”运算,如

  1. 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)操作

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

返回值:返回实际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动。

参数

fd:表示文件句柄,是由open函数得到

buf:read()函数会把fd 所指的文件传送count个字节到buf指针所指的内存中

size:要读取的字节数



4、写入操作

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

返回值 :如果成功write(),就会返回实际写入的字节数。当有错误发生时则返回-1

参数

fd:同上

buf:将要写入到文件里面的内容。

size:要写入的字节数


5、跳转操作

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

返回值:成功时则返回目前的读写位置,也就是距离文件开头多少个字节,若有错误则返回-1。

参数

fd:同上

pos:跳转的相对量,可正可负,表示相对位置的前后关系

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

  1. int SEEK_SET   =        0;//将读写位置指向文件头后再增加offset个位移量。  
  2. int SEEK_CUR   =        1;//以目前的读写位置往后增加offset个位移量。  
  3. int EEK_END    =        2;//将读写位置指向文件尾后再增加offset个位移量。  

注:当size参数=0;whence = SEEK_END;时返回值即为文件大小。


6、关闭操作

  1. int close(int fd)  


7、简单示例

效果图:





7.1、JNI代码:(有JNI_onLoad函数)

  1. //fs.c  
  2. #include <unistd.h>  
  3. #include <sys/stat.h>  
  4. #include <sys/time.h>  
  5. #include <stdlib.h>  
  6. #include <fcntl.h>  
  7.   
  8.   
  9.  int file_open(const char *filename, int flags)  
  10. {  
  11.     int fd;  
  12.     
  13.     fd = open(filename, flags, 0666);  
  14.     if (fd == -1)  
  15.         return -1;  
  16.   
  17.     return fd;  
  18. }  
  19.   
  20.  int file_read(int fd, unsigned char *buf, int size)  
  21. {  
  22.       
  23.     return read(fd, buf, size);  
  24. }  
  25.   
  26.  int file_write(int fd, const unsigned char *buf, int size)  
  27. {  
  28.       
  29.     return write(fd, buf, size);  
  30. }  
  31.   
  32.   
  33.  int64_t file_seek(int fd, int64_t pos, int whence)  
  34. {  
  35.       
  36.     if (whence == 0x10000) {  
  37.         struct stat st;  
  38.         int ret = fstat(fd, &st);  
  39.         return ret < 0 ? -1 : st.st_size;  
  40.     }  
  41.     return lseek(fd, pos, whence);  
  42. }  
  43.   
  44.  int file_close(int fd)  
  45. {  
  46.      
  47.     return close(fd);  
  48. }  

  1. //jni.c  
  2. #define TAG "fs_jni"  
  3.   
  4. #include <android/log.h>  
  5. #include "jniUtils.h"  
  6.   
  7.   
  8.   
  9. static const charconst kClassPathName = "com/conowen/fs/FsActivity";  
  10.   
  11.   
  12. jint  
  13. Java_com_conowen_fs_FsActivity_NativeFileOpen( JNIEnv* env, jobject thiz,jstring filename,jint flags ){     
  14.   
  15.       
  16.      const char *filename_char = (*env)->GetStringUTFChars(env,filename, NULL);  
  17.    
  18.     return file_open(filename_char, flags);  
  19. }  
  20. jint  
  21. Java_com_conowen_fs_FsActivity_NativeFileRead(JNIEnv* env, jobject thiz,int fd,jbyteArray buf,jint size){  
  22.   
  23.     unsigned char *buf_char = (char*)((*env)->GetByteArrayElements(env,buf, NULL));  
  24.   
  25.     return file_read(fd, buf_char,  size);  
  26. }  
  27.   
  28. jint  
  29. Java_com_conowen_fs_FsActivity_NativeFileWrite(JNIEnv* env, jobject thiz,int fd,jbyteArray buf,jint size){  
  30.       
  31.     unsigned char *buf_char = (char*)((*env)->GetByteArrayElements(env,buf, NULL));  
  32.   
  33.     return file_write(fd, buf_char,  size);  
  34. }  
  35.   
  36. jlong  
  37. Java_com_conowen_fs_FsActivity_NativeFileSeek(JNIEnv* env, jobject thiz,int fd,jlong Offset,jint whence){  
  38.   
  39.     return file_seek(fd, Offset,  whence);  
  40. }  
  41.   
  42. jint  
  43. Java_com_conowen_fs_FsActivity_NativeFileClose(JNIEnv* env, jobject thiz,int fd){  
  44.   
  45.     return file_close(fd);  
  46. }  
  47.   
  48. /******************************JNI registration.************************************/  
  49. static JNINativeMethod gMethods[] = {  
  50.     {"NativeFileOpen",       "(Ljava/lang/String;I)I",           (void *)Java_com_conowen_fs_FsActivity_NativeFileOpen},  
  51.     {"NativeFileRead",       "(I[BI)I",                          (void *)Java_com_conowen_fs_FsActivity_NativeFileRead},  
  52.     {"NativeFileWrite",      "(I[BI)I",                          (void *)Java_com_conowen_fs_FsActivity_NativeFileWrite},  
  53.     {"NativeFileSeek",       "(IJI)J",                           (void *)Java_com_conowen_fs_FsActivity_NativeFileSeek},  
  54.     {"NativeFileClose",      "(I)I",                             (void *)Java_com_conowen_fs_FsActivity_NativeFileClose},  
  55. };  
  56.   
  57. int register_com_conowen_fs_FsActivity(JNIEnv *env) {  
  58.     return jniRegisterNativeMethods(env, kClassPathName, gMethods, sizeof(gMethods) / sizeof(gMethods[0]));  
  59.       
  60. }  

  1. //jniUtils.h  
  2. #ifndef _JNI_UTILS_H_  
  3. #define _JNI_UTILS_H_  
  4.   
  5. #include <stdlib.h>  
  6. #include <jni.h>  
  7.   
  8. #ifdef __cplusplus  
  9. extern "C"  
  10. {  
  11. #endif  
  12.   
  13. int jniThrowException(JNIEnv* env, const char* className, const char* msg);  
  14.   
  15. JNIEnv* getJNIEnv();  
  16.   
  17. int jniRegisterNativeMethods(JNIEnv* env,  
  18.                              const char* className,  
  19.                              const JNINativeMethod* gMethods,  
  20.                              int numMethods);  
  21.   
  22. #ifdef __cplusplus  
  23. }  
  24. #endif  
  25.   
  26. #endif /* _JNI_UTILS_H_ */  

  1. //onLoad.cpp  
  2. #define TAG "fs_onLoad"  
  3.   
  4. #include <android/log.h>  
  5. #include "jniUtils.h"  
  6.   
  7. extern "C" {  
  8.   
  9. extern int register_com_conowen_fs_FsActivity(JNIEnv *env);  
  10.   
  11. }  
  12.   
  13. static JavaVM *sVm;  
  14.   
  15. /* 
  16.  * Throw an exception with the specified class and an optional message. 
  17.  */  
  18. int jniThrowException(JNIEnv* env, const char* className, const char* msg) {  
  19.     jclass exceptionClass = env->FindClass(className);  
  20.     if (exceptionClass == NULL) {  
  21.         __android_log_print(ANDROID_LOG_ERROR,  
  22.                 TAG,  
  23.                 "Unable to find exception class %s",  
  24.                         className);  
  25.         return -1;  
  26.     }  
  27.   
  28.     if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {  
  29.         __android_log_print(ANDROID_LOG_ERROR,  
  30.                 TAG,  
  31.                 "Failed throwing '%s' '%s'",  
  32.                 className, msg);  
  33.     }  
  34.     return 0;  
  35. }  
  36.   
  37. JNIEnv* getJNIEnv() {  
  38.     JNIEnv* env = NULL;  
  39.     if (sVm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  40.         __android_log_print(ANDROID_LOG_ERROR,  
  41.                             TAG,  
  42.                             "Failed to obtain JNIEnv");  
  43.         return NULL;  
  44.     }  
  45.     return env;  
  46. }  
  47.   
  48. /* 
  49.  * Register native JNI-callable methods. 
  50.  * 
  51.  * "className" looks like "java/lang/String". 
  52.  */  
  53. int jniRegisterNativeMethods(JNIEnv* env,  
  54.                              const char* className,  
  55.                              const JNINativeMethod* gMethods,  
  56.                              int numMethods)  
  57. {  
  58.     jclass clazz;  
  59.   
  60.     __android_log_print(ANDROID_LOG_INFO, TAG, "Registering %s natives\n", className);  
  61.     clazz = env->FindClass(className);  
  62.     if (clazz == NULL) {  
  63.         __android_log_print(ANDROID_LOG_ERROR, TAG, "Native registration unable to find class '%s'\n", className);  
  64.         return -1;  
  65.     }  
  66.     if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {  
  67.         __android_log_print(ANDROID_LOG_ERROR, TAG, "RegisterNatives failed for '%s'\n", className);  
  68.         return -1;  
  69.     }  
  70.     return 0;  
  71. }  
  72. //Dalvik虚拟机加载C库时,第一件事是调用JNI_OnLoad()函数  
  73. jint JNI_OnLoad(JavaVM* vm, void* reserved) {  
  74.     JNIEnv* env = NULL;  
  75.     jint result = JNI_ERR;  
  76.     sVm = vm;  
  77.   
  78.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  79.         __android_log_print(ANDROID_LOG_ERROR, TAG, "GetEnv failed!");  
  80.         return result;  
  81.     }  
  82.   
  83.     __android_log_print(ANDROID_LOG_INFO, TAG, "loading . . .");  
  84.   
  85.   
  86.     if(register_com_conowen_fs_FsActivity(env) != JNI_OK) {  
  87.         __android_log_print(ANDROID_LOG_ERROR, TAG, "can't load register_com_conowen_fs_FsActivity");  
  88.         goto end;  
  89.     }  
  90.   
  91.     __android_log_print(ANDROID_LOG_INFO, TAG, "loaded");  
  92.   
  93.     result = JNI_VERSION_1_4;  
  94.   
  95. end:  
  96.     return result;  
  97. }  

7.2、Android.mk文件


  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    := fs  
  6. LOCAL_SRC_FILES := fs.c jni.c onLoad.cpp  
  7. LOCAL_LDLIBS  += -llog  
  8.   
  9. include $(BUILD_SHARED_LIBRARY)  


7.3、java层代码

  1. /* author:conowen 
  2.  * data:2012.5.1 
  3.  * e-mail:conowen@hotmail.com 
  4.  */  
  5. package com.conowen.fs;  
  6.   
  7. import java.io.UnsupportedEncodingException;  
  8.   
  9. import android.app.Activity;  
  10. import android.os.Bundle;  
  11. import android.view.View;  
  12. import android.view.View.OnClickListener;  
  13. import android.widget.Button;  
  14. import android.widget.EditText;  
  15. import android.widget.TextView;  
  16.   
  17. public class FsActivity extends Activity {  
  18.     String filename = "/sdcard/test.txt";  
  19.     EditText writestrET;  
  20.     Button writeBT;  
  21.     Button readBT;  
  22.     Button seekBT;  
  23.     TextView readTV;  
  24.     String writeStr;  
  25.     byte[] buf_write;  
  26.     byte[] buf_read;  
  27.     int fd;  
  28.       
  29.     int O_ACCMODE  =    0003;  
  30.     int O_RDONLY   =      00;  
  31.     int O_WRONLY   =      01;  
  32.     int O_RDWR     =      02;  
  33.     int O_CREAT    =    0100/* not fcntl */  
  34.     int O_EXCL     =    0200/* not fcntl */  
  35.     int O_NOCTTY   =   0400/* not fcntl */  
  36.     int O_TRUNC    =   01000/* not fcntl */  
  37.     int O_APPEND   =   02000;  
  38.     int O_NONBLOCK =   04000;  
  39.     int O_NDELAY   = O_NONBLOCK;  
  40.     int O_SYNC     =  010000;  
  41.     int O_FSYNC    =  O_SYNC;  
  42.     int O_ASYNC    =  020000;  
  43.       
  44.     int SEEK_SET   =        0;//将读写位置指向文件头后再增加offset个位移量。  
  45.     int SEEK_CUR   =        1;//以目前的读写位置往后增加offset个位移量。  
  46.     int EEK_END    =        2;//将读写位置指向文件尾后再增加offset个位移量。   
  47.       
  48.     /** Called when the activity is first created. */  
  49.     @Override  
  50.     public void onCreate(Bundle savedInstanceState) {  
  51.         super.onCreate(savedInstanceState);  
  52.         setContentView(R.layout.main);  
  53.         writestrET = (EditText) findViewById(R.id.writeET);  
  54.         writeBT = (Button) findViewById(R.id.writeBT);  
  55.         readBT = (Button) findViewById(R.id.readBT);  
  56.         seekBT = (Button) findViewById(R.id.seekBT);  
  57.         readTV = (TextView) findViewById(R.id.readTV);  
  58.         writeBT.setOnClickListener(new OnClickListener() {  
  59.   
  60.             @Override  
  61.             public void onClick(View v) {  
  62.                 // TODO Auto-generated method stub  
  63.                 fd = NativeFileOpen(filename, O_CREAT  | O_RDWR);  
  64.                 System.out.println("fd_write---->" + fd);  
  65.                 writeStr = writestrET.getText().toString();  
  66.                 buf_write = writeStr.getBytes();  
  67.                 int ret_write = NativeFileWrite(fd, buf_write, buf_write.length);  
  68.                 System.out.println("写入返回结果" + ret_write);  
  69.                 NativeFileClose(fd);  
  70.   
  71.             }  
  72.         });  
  73.         readBT.setOnClickListener(new OnClickListener() {  
  74.   
  75.             @Override  
  76.             public void onClick(View v) {  
  77.                 // TODO Auto-generated method stub  
  78.                 fd = NativeFileOpen(filename, O_CREAT  | O_RDWR);  
  79.                 System.out.println("fd_read---->" + fd);  
  80.                 buf_read = new byte[buf_write.length];  
  81.                 int ret_read = NativeFileRead(fd, buf_read, buf_write.length);  
  82.                   
  83.                 System.out.println("读出返回结果" + ret_read);  
  84.                 try {  
  85.                     readTV.setText( new String(buf_read, "GB2312") + "");  
  86.                 } catch (UnsupportedEncodingException e) {  
  87.                     // TODO Auto-generated catch block  
  88.                     e.printStackTrace();  
  89.                 }  
  90.                 NativeFileClose(fd);  
  91.             }  
  92.         });  
  93.         seekBT.setOnClickListener(new OnClickListener() {  
  94.   
  95.             @Override  
  96.             public void onClick(View v) {  
  97.                 // TODO Auto-generated method stub  
  98.                 fd = NativeFileOpen(filename, O_CREAT  | O_RDWR);  
  99.                 long Offset=20;  
  100.                 long ret_seek =NativeFileSeek(fd, Offset, SEEK_CUR);  
  101.               
  102.                 System.out.println("seek返回结果" + ret_seek);  
  103.                   
  104.                 NativeFileClose(fd);  
  105.                 /*    1) 欲将读写位置移到文件开头时: 
  106.                          lseek(int fildes,0,SEEK_SET); 
  107.                      2) 欲将读写位置移到文件尾时: 
  108.                          lseek(int fildes,0,SEEK_END); 
  109.                      3) 想要取得目前文件位置时: 
  110.                          lseek(int fildes,0,SEEK_CUR); 
  111.                 返回值:当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。若有错误则返回-1,errno 会存放错误代码。 
  112.                  * */  
  113.             }  
  114.         });  
  115.   
  116.     }  
  117.   
  118.     public native int NativeFileOpen(String filename, int flags);  
  119.   
  120.     public native int NativeFileRead(int fd, byte[] buf, int sizes);  
  121.   
  122.     public native int NativeFileWrite(int fd, byte[] buf, int sizes);  
  123.   
  124.     public native long NativeFileSeek(int fd, long Offset, int whence);  
  125.     //Offset:偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(向前移,向后移)。  
  126.   
  127.     public native int NativeFileClose(int fd);  
  128.   
  129.     static {  
  130.         System.loadLibrary("fs");  
  131.     }  
  132. }  


最后记得在manifest.xml里面加上SD卡操作权限

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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多