Jni 两种方法打开底层文件返回FD给Java

打开文件

在底层open一个文件时只是返回一个fd号,而Java打开一个文件用的是FileDescriptor来打开一个文件,如何在两者之间建立一个联系呢?有两种方法:

方法一:在jni层有提供一个API,jniCreateFileDescriptor(env, fd); 生成的是一个临时变量,最终还是要通过NewObject创建一个对象才能return回去。在Android.mk里还要加入这些库,这些库从系统里的jni的Android.mk里抄过来的,jniCreateFileDescriptor要用到的是哪个库还有待研究。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   jclass clazz = env->FindClass( "android/os/ParcelFileDescriptor" );
if (clazz == NULL){
     XLOGE( "Unable to find class android.os.ParcelFileDescriptor" ); 
     return  -1;
}
 
   gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
   gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz,  "<init>" "(Ljava/io/FileDescriptor;)V" ); 
 
    jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
if (fileDescriptor == NULL){
     XLOGE( "jniCreateFileDescriptor error" );
     return  NULL;
}
 
return  env->NewObject(gParcelFileDescriptorOffsets.mClass,
     gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);

Android.mk用到的库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
LOCAL_SHARED_LIBRARIES := \
     libandroid_runtime \
     libandroidfw \
     libbinder \
     libcutils \
     liblog \
     libhardware \
     libhardware_legacy \
     libnativehelper \
     libutils \
     libui \
     libinput \
     libinputservice \
     libsensorservice \
     libskia \
     libgui \
     libusbhost \
     libsuspend \
     libdl \
     libEGL \
     libGLESv2

方法二:

直接创建找到这个类,并调用这个对象的构建函数创建这个对象

1
2
3
4
5
6
7
8
/* Create a corresponding file descriptor */
{
     jclass cFileDescriptor = env->FindClass( "java/io/FileDescriptor" );
     jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor,  "<init>" "()V" );
     jfieldID descriptorID = env->GetFieldID(cFileDescriptor,  "descriptor" "I" );
     mFileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);
     env->SetIntField(mFileDescriptor, descriptorID, (jint)fd);
}

关闭文件

关闭文件也有两种文件

一. 在打开的时候把fd保存为全局变量,关闭的时候只要close(fd)。即可

二. 这是一个比较显高端的方法,就是找到打开这个文件的类,然后在这里类里找到FileDescriptor变量,再找出该FileDescriptor对象里的fd变量,关闭fd即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void  closeFile(JNIEnv *env, jobject thiz){
     //根据对象this获取这个对象的类
     jclass SerialPortClass = env->GetObjectClass(thiz);
     //找出FileDescriptor类
     jclass FileDescriptorClass = env->FindClass(  "java/io/FileDescriptor" );
     
     //在SerialPortClass这个类里找出mFd这个变量的ID,这个变量的类型是FileDescriptor
     jfieldID mFdID = env->GetFieldID(SerialPortClass,  "mFd" , "Ljava/io/FileDescriptor;" );
     //在FileDescriptor里找出descriptor的ID,这是一个整型。就是我们用open打开返回的那个fd
     jfieldID descriptorID = env->GetFieldID(FileDescriptorClass,  "descriptor" "I" );
 
     //根据上面找出来的mFd的ID,从在erialPortClass这个类里找出mFd这个实例变量
     jobject mFd = env->GetObjectField(thiz, mFdID);
     //根据上面找出来的mFd的实例变量,再从里面这个类里找出mFD实例变量里的descriptor
     jint descriptor = env->GetIntField(mFd, descriptorID);
 
     close(descriptor);
}


猜你喜欢

转载自blog.csdn.net/shell812/article/details/49763195
今日推荐