Android的NDK开发(5)————Android(安卓)JNI层实现文件的read、write与seek操作
/********************************************************************************************
* 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、打开文件
[cpp] view plain copy print ?- intopen(constchar*pathname,intflags,intmode);
返回值:为一个文件句柄(fd),供read、write等操作。
参数:
pathname: 打开的文件所在路径字符串。如
[java] view plain copy print ?- Stringfilename="/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)操作
- intread(intfd,unsignedchar*buf,intsize);
返回值:返回实际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动。
参数:
fd:表示文件句柄,是由open函数得到
buf:read()函数会把fd 所指的文件传送count个字节到buf指针所指的内存中
size:要读取的字节数
4、写入操作
- intwrite(intfd,constunsignedchar*buf,intsize);
返回值 :如果成功write(),就会返回实际写入的字节数。当有错误发生时则返回-1
参数:
fd:同上
buf:将要写入到文件里面的内容。
size:要写入的字节数
5、跳转操作
[cpp] view plain copy print ?- int64_tseek(intfd,int64_tpos,intwhence)
返回值:成功时则返回目前的读写位置,也就是距离文件开头多少个字节,若有错误则返回-1。
参数:
fd:同上
pos:跳转的相对量,可正可负,表示相对位置的前后关系
whence:跳转的方向,whence取值如下所示
[cpp] view plain copy print ?- intSEEK_SET=0;//将读写位置指向文件头后再增加offset个位移量。
- intSEEK_CUR=1;//以目前的读写位置往后增加offset个位移量。
- intEEK_END=2;//将读写位置指向文件尾后再增加offset个位移量。
注:当size参数=0;whence = SEEK_END;时返回值即为文件大小。
6、关闭操作
[cpp] view plain copy print ?- intclose(intfd)
7、简单示例
效果图:
7.1、JNI代码:(有JNI_onLoad函数)
[cpp] view plain copy print ?- //fs.c
- #include<unistd.h>
- #include<sys/stat.h>
- #include<sys/time.h>
- #include<stdlib.h>
- #include<fcntl.h>
- intfile_open(constchar*filename,intflags)
- {
- intfd;
- fd=open(filename,flags,0666);
- if(fd==-1)
- return-1;
- returnfd;
- }
- intfile_read(intfd,unsignedchar*buf,intsize)
- {
- returnread(fd,buf,size);
- }
- intfile_write(intfd,constunsignedchar*buf,intsize)
- {
- returnwrite(fd,buf,size);
- }
- int64_tfile_seek(intfd,int64_tpos,intwhence)
- {
- if(whence==0x10000){
- structstatst;
- intret=fstat(fd,&st);
- returnret<0?-1:st.st_size;
- }
- returnlseek(fd,pos,whence);
- }
- intfile_close(intfd)
- {
- returnclose(fd);
- }
[cpp] view plain copy print ?
- //jni.c
- #defineTAG"fs_jni"
- #include<android/log.h>
- #include"jniUtils.h"
- staticconstchar*constkClassPathName="com/conowen/fs/FsActivity";
- jint
- Java_com_conowen_fs_FsActivity_NativeFileOpen(JNIEnv*env,jobjectthiz,jstringfilename,jintflags){
- constchar*filename_char=(*env)->GetStringUTFChars(env,filename,NULL);
- returnfile_open(filename_char,flags);
- }
- jint
- Java_com_conowen_fs_FsActivity_NativeFileRead(JNIEnv*env,jobjectthiz,intfd,jbyteArraybuf,jintsize){
- unsignedchar*buf_char=(char*)((*env)->GetByteArrayElements(env,buf,NULL));
- returnfile_read(fd,buf_char,size);
- }
- jint
- Java_com_conowen_fs_FsActivity_NativeFileWrite(JNIEnv*env,jobjectthiz,intfd,jbyteArraybuf,jintsize){
- unsignedchar*buf_char=(char*)((*env)->GetByteArrayElements(env,buf,NULL));
- returnfile_write(fd,buf_char,size);
- }
- jlong
- Java_com_conowen_fs_FsActivity_NativeFileSeek(JNIEnv*env,jobjectthiz,intfd,jlongOffset,jintwhence){
- returnfile_seek(fd,Offset,whence);
- }
- jint
- Java_com_conowen_fs_FsActivity_NativeFileClose(JNIEnv*env,jobjectthiz,intfd){
- returnfile_close(fd);
- }
- /******************************JNIregistration.************************************/
- staticJNINativeMethodgMethods[]={
- {"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},
- };
- intregister_com_conowen_fs_FsActivity(JNIEnv*env){
- returnjniRegisterNativeMethods(env,kClassPathName,gMethods,sizeof(gMethods)/sizeof(gMethods[0]));
- }
[cpp] view plain copy print ?
- //jniUtils.h
- #ifndef_JNI_UTILS_H_
- #define_JNI_UTILS_H_
- #include<stdlib.h>
- #include<jni.h>
- #ifdef__cplusplus
- extern"C"
- {
- #endif
- intjniThrowException(JNIEnv*env,constchar*className,constchar*msg);
- JNIEnv*getJNIEnv();
- intjniRegisterNativeMethods(JNIEnv*env,
- constchar*className,
- constJNINativeMethod*gMethods,
- intnumMethods);
- #ifdef__cplusplus
- }
- #endif
- #endif/*_JNI_UTILS_H_*/
[cpp] view plain copy print ?
- //onLoad.cpp
- #defineTAG"fs_onLoad"
- #include<android/log.h>
- #include"jniUtils.h"
- extern"C"{
- externintregister_com_conowen_fs_FsActivity(JNIEnv*env);
- }
- staticJavaVM*sVm;
- /*
- *Throwanexceptionwiththespecifiedclassandanoptionalmessage.
- */
- intjniThrowException(JNIEnv*env,constchar*className,constchar*msg){
- jclassexceptionClass=env->FindClass(className);
- if(exceptionClass==NULL){
- __android_log_print(ANDROID_LOG_ERROR,
- TAG,
- "Unabletofindexceptionclass%s",
- className);
- return-1;
- }
- if(env->ThrowNew(exceptionClass,msg)!=JNI_OK){
- __android_log_print(ANDROID_LOG_ERROR,
- TAG,
- "Failedthrowing'%s''%s'",
- className,msg);
- }
- return0;
- }
- JNIEnv*getJNIEnv(){
- JNIEnv*env=NULL;
- if(sVm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK){
- __android_log_print(ANDROID_LOG_ERROR,
- TAG,
- "FailedtoobtainJNIEnv");
- returnNULL;
- }
- returnenv;
- }
- /*
- *RegisternativeJNI-callablemethods.
- *
- *"className"lookslike"java/lang/String".
- */
- intjniRegisterNativeMethods(JNIEnv*env,
- constchar*className,
- constJNINativeMethod*gMethods,
- intnumMethods)
- {
- jclassclazz;
- __android_log_print(ANDROID_LOG_INFO,TAG,"Registering%snatives\n",className);
- clazz=env->FindClass(className);
- if(clazz==NULL){
- __android_log_print(ANDROID_LOG_ERROR,TAG,"Nativeregistrationunabletofindclass'%s'\n",className);
- return-1;
- }
- if(env->RegisterNatives(clazz,gMethods,numMethods)<0){
- __android_log_print(ANDROID_LOG_ERROR,TAG,"RegisterNativesfailedfor'%s'\n",className);
- return-1;
- }
- return0;
- }
- //Dalvik虚拟机加载C库时,第一件事是调用JNI_OnLoad()函数
- jintJNI_OnLoad(JavaVM*vm,void*reserved){
- JNIEnv*env=NULL;
- jintresult=JNI_ERR;
- sVm=vm;
- if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK){
- __android_log_print(ANDROID_LOG_ERROR,TAG,"GetEnvfailed!");
- returnresult;
- }
- __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'tloadregister_com_conowen_fs_FsActivity");
- gotoend;
- }
- __android_log_print(ANDROID_LOG_INFO,TAG,"loaded");
- result=JNI_VERSION_1_4;
- end:
- returnresult;
- }
7.2、Android.mk文件
- LOCAL_PATH:=$(callmy-dir)
- include$(CLEAR_VARS)
- LOCAL_MODULE:=fs
- LOCAL_SRC_FILES:=fs.cjni.conLoad.cpp
- LOCAL_LDLIBS+=-llog
- include$(BUILD_SHARED_LIBRARY)
7.3、java层代码
[java] view plain copy print ?- /*author:conowen
- *data:2012.5.1
- *e-mail:conowen@hotmail.com
- */
- packagecom.conowen.fs;
- importjava.io.UnsupportedEncodingException;
- importandroid.app.Activity;
- importandroid.os.Bundle;
- importandroid.view.View;
- importandroid.view.View.OnClickListener;
- importandroid.widget.Button;
- importandroid.widget.EditText;
- importandroid.widget.TextView;
- publicclassFsActivityextendsActivity{
- Stringfilename="/sdcard/test.txt";
- EditTextwritestrET;
- ButtonwriteBT;
- ButtonreadBT;
- ButtonseekBT;
- TextViewreadTV;
- StringwriteStr;
- byte[]buf_write;
- byte[]buf_read;
- intfd;
- intO_ACCMODE=0003;
- intO_RDONLY=00;
- intO_WRONLY=01;
- intO_RDWR=02;
- intO_CREAT=0100;/*notfcntl*/
- intO_EXCL=0200;/*notfcntl*/
- intO_NOCTTY=0400;/*notfcntl*/
- intO_TRUNC=01000;/*notfcntl*/
- intO_APPEND=02000;
- intO_NONBLOCK=04000;
- intO_NDELAY=O_NONBLOCK;
- intO_SYNC=010000;
- intO_FSYNC=O_SYNC;
- intO_ASYNC=020000;
- intSEEK_SET=0;//将读写位置指向文件头后再增加offset个位移量。
- intSEEK_CUR=1;//以目前的读写位置往后增加offset个位移量。
- intEEK_END=2;//将读写位置指向文件尾后再增加offset个位移量。
- /**Calledwhentheactivityisfirstcreated.*/
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- 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(newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- fd=NativeFileOpen(filename,O_CREAT|O_RDWR);
- System.out.println("fd_write---->"+fd);
- writeStr=writestrET.getText().toString();
- buf_write=writeStr.getBytes();
- intret_write=NativeFileWrite(fd,buf_write,buf_write.length);
- System.out.println("写入返回结果"+ret_write);
- NativeFileClose(fd);
- }
- });
- readBT.setOnClickListener(newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- fd=NativeFileOpen(filename,O_CREAT|O_RDWR);
- System.out.println("fd_read---->"+fd);
- buf_read=newbyte[buf_write.length];
- intret_read=NativeFileRead(fd,buf_read,buf_write.length);
- System.out.println("读出返回结果"+ret_read);
- try{
- readTV.setText(newString(buf_read,"GB2312")+"");
- }catch(UnsupportedEncodingExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- NativeFileClose(fd);
- }
- });
- seekBT.setOnClickListener(newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- fd=NativeFileOpen(filename,O_CREAT|O_RDWR);
- longOffset=20;
- longret_seek=NativeFileSeek(fd,Offset,SEEK_CUR);
- System.out.println("seek返回结果"+ret_seek);
- NativeFileClose(fd);
- /* 1)欲将读写位置移到文件开头时:
- lseek(intfildes,0,SEEK_SET);
- 2)欲将读写位置移到文件尾时:
- lseek(intfildes,0,SEEK_END);
- 3)想要取得目前文件位置时:
- lseek(intfildes,0,SEEK_CUR);
- 返回值:当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。若有错误则返回-1,errno会存放错误代码。
- **/
- }
- });
- }
- publicnativeintNativeFileOpen(Stringfilename,intflags);
- publicnativeintNativeFileRead(intfd,byte[]buf,intsizes);
- publicnativeintNativeFileWrite(intfd,byte[]buf,intsizes);
- publicnativelongNativeFileSeek(intfd,longOffset,intwhence);
- //Offset:偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(向前移,向后移)。
- publicnativeintNativeFileClose(intfd);
- static{
- System.loadLibrary("fs");
- }
- }
最后记得在manifest.xml里面加上SD卡操作权限
[html] view plain copy print ?- <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
更多相关文章
- NPM 和webpack 的基础使用
- 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
- windows下搭建cocos2dx Android开发环境
- Android(安卓)文件操作
- android 判断联网类型
- Android手机拍照和手机相册选取图片的工具类ImageUtils
- android之File
- Android(安卓)Ant打包及其环境变量配置
- Android(安卓)时区的修改增删,如何在菜单里增加一个没有的时区