zoukankan      html  css  js  c++  java
  • Android的NDK开发(5)————Android JNI层实现文件的read、write与seek操作

    原文: http://blog.csdn.net/conowen/article/details/7525837


    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: 打开的文件所在路径字符串。如

    [java] view plaincopy
    1. String filename = "/sdcard/test.txt";  

    flags: 文件打开的方式

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

    [java] view plaincopy
    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层代码

    [java] view plaincopy
    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卡操作权限

    [html] view plaincopy
    1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
    2. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  


  • 相关阅读:
    php错误抑制符
    php执行运算符
    php中一个经典的!==的用法
    php实现简单验证码的功能
    jquery是什么
    php连接符
    php与java语法的区别
    考雅思策略
    php魔术常量
    PHP中数据类型转换的三种方式
  • 原文地址:https://www.cnblogs.com/java20130722/p/3207325.html
Copyright © 2011-2022 走看看