Android中JNI调用–文件操作

JNI 是 Java Native Interface 的缩写,译为 Java 本地接口。它允许 Java 代码和其他语言编写的代码进行交互。在android 中提供 JNI 的方式,让 Java 程序可以调用 C/C++语言程序。 android 中很多 Java 类都具有 native 接口,这些接口由本地实现,然后注册到系统中。


1、开发环境

Windows xp sp3 +MyEclipse 8.6+android2.3.3+jdk1.6+Android-ndk-r6b

2、JNI概述

JNI 是 Java Native Interface 的缩写,译为 Java 本地接口。它允许 Java 代码和其他语言编写的代码进行交互。在android 中提供 JNI 的方式,让 Java 程序可以调用 C/C++语言程序。 android 中很多 Java 类都具有 native 接口,这些接口由本地实现,然后注册到系统中。在android系统中实现JNI库需要连接.so共享库,如:lib<文件名>.so。

3、Android NDK概述

Android NDK是一个工具集,让你的Android应用程序里可以内嵌使用本地代码(C/C++)的组件。
Android应用程序运行在Dalvik虚拟机中。NDK可以让你使用C/C++这样的本地代码语言来实现你的应用程序中某些部分。这对某类程序是有帮助的,比如需要重用已有的C代码,或者为了提高运行速度

NDK 提供:
– 编译文件和工具集,用来将你的C/C++源文件编译成本地库。
– 提供一种方式,将对应的本地库内嵌到应用程序包文件(.apk)中,最终发布到Android设备中。
– 本地系统头文件和库,这些头文件和库从Android1.5开始往后都是被支持的。但使用本地活动(native activity)的程序只能运行在Android 2.3或更高的系统中。
– 文档、示例、指南。

4、JNI调用流程图


5、java调用Native

Android虚拟机允许你的应用程序源代码通过JNI调用实现本地代码的方法,需要在应用程序中使用关键字native声明一个或多个方法表明该方法是通过本地调用实现的,如:

public native static int FileOpen(StringpFileName,int openMode);
public native static int FileLength(int fp);
public native static int FileSeek(int fp,int offset,int origin);
public native static CusBuffer FileRead(int fp,int nCount);
public native static int FileWrite(int fp,byte[] buf,int nCount);
public native static int FileClose(int fp);

除了声明native方法以外还必须为这些方法实现提供本地共享库,该共享库最终会被打包到.apk文件中,这些共享库需要更具标准的unix公约来命名lib<文件名>.so,如:libJNI_FileSys.so,其中JNI_FileSys使我们需要加载的库名。在应用程序中加载共享库的方法为:

static{
    System.loadLibrary("JNI_FileSys");
}

注:这里使用的文件名不需要lib前缀以及.so后缀名。

FileSys.java完整代码实现:

package com.luoxudong.jni.reader;
import com.luoxudong.jni.bean.CusBuffer;
    
/********************************************************************
* [Summary]
    
*   TODO 文件操作类
* [Remarks]
*   TODO 请在此处详细描述类的功能、调用方法、注意事项、以及与其它类的关系.
 ********************************************************************/
public class FileSys {
static{
    System.loadLibrary("JNI_FileSys");
}
    
/**
 *
 * [Summary]
 *   MjFileOpen 打开文件
 * @param strFileName 文件名
 * @param openMode 打开类型
 * @return 结果
 *
 */
public int MjFileOpen(String strFileName,int openMode){
    return FileOpen(strFileName, openMode);
}

/**
 *
 * [Summary]
 *   MjFileLength 计算文件长度
 * @param fp 文件句柄
 * @return 文件长度
 *
 */
public int MjFileLength(int fp){
    return FileLength(fp);
}
    
/**
 *
 * [Summary]
 *   MjFileSeek 文件seek操作
 * @param fp 文件句柄
 * @param offset 读取数据偏移量
 * @param origin 开始位置指针
 * @return
 *
 */
public int MjFileSeek(int fp,int offset,int origin){
	return FileSeek(fp, offset, origin);
} 

/**
 *
 * [Summary]
 *   MjFileRead 读取文件数据
 * @param fp 文件句柄
 * @param nCount 读取字节数
 * @return 实际读取字节数
 *
 */
public CusBuffer MjFileRead(int fp,int nCount){
   return FileRead(fp, nCount);
}

/**
 *
 * [Summary]
 *   MjFileWrite 写文件
 * @param fp 文件句柄
 * @param buf 写数据buffer
 * @param nCount 需要写入的字节数
 * @return 实际写入字节数
 *
 */
public int MjFileWrite(int fp,byte[] buf,int nCount){
    return FileWrite(fp, buf, nCount);
}

/**
 *
 * [Summary]
 *   MjFileClose 关闭文件
 * @param fp 文件句柄
 * @return 关闭文件状态
 *
 */
public int MjFileClose(int fp){
	return FileClose(fp);
}

//本地调用
public native static int FileOpen(String pFileName,int openMode);
public native static int FileLength(int fp);
public native static int FileSeek(int fp,int offset,int origin);
public native static CusBuffer FileRead(int fp,int nCount);
public native static int FileWrite(int fp,byte[] buf,int nCount);
public native static int FileClose(int fp);
}

6、实现本地方法调用接口

为了方便我们可以使用javah命令先生成对应C/C++语言中的.h然后再实现这些函数。FileSys.java编译成FileSys.class文件后,使用命令(当前目录为工程bin目录下)javah -jni com.luoxudong.jni.reader.FileSys,此时会在bin目录下生成一个.h文件,文件名格式如下:com_luoxudong_jni_reader_FileSys.h,为了方便本人把文件名改成JNI_FileSys.h。
JNI_FileSys.h代码:

/* DO NOT EDIT THISFILE - it is machine generated */
#include<jni.h>
/* Header for classcom_meijin_dict_reader_FileSys */
    
#ifndef_Included_com_meijin_dict_reader_FileSys
#define_Included_com_meijin_dict_reader_FileSys
#ifdef __cplusplus
extern"C" {
#endif
    /*
    * Class:com_meijin_dict_reader_FileSys
    * Method:   FileOpen
    * Signature: (Ljava/lang/String;I)I
    */
    JNIEXPORT jintJNICALL Java_com_meijin_dict_reader_FileSys_FileOpen
      (JNIEnv *, jclass, jstring, jint);
    
    /*
    * Class:com_meijin_dict_reader_FileSys
    * Method:   FileLength
    * Signature: (I)I
    */
    JNIEXPORT jintJNICALL Java_com_meijin_dict_reader_FileSys_FileLength
      (JNIEnv *, jclass, jint);
    
    /*
    * Class:com_meijin_dict_reader_FileSys
    * Method:   FileSeek
    * Signature: (III)I
    */
    JNIEXPORT jintJNICALL Java_com_meijin_dict_reader_FileSys_FileSeek
      (JNIEnv *, jclass, jint, jint, jint);
    
    /*
    * Class:com_meijin_dict_reader_FileSys
    * Method:   FileRead
    * Signature:(II)Lcom/meijin/dict/bean/CusBuffer;
    */
    JNIEXPORT jobjectJNICALL Java_com_meijin_dict_reader_FileSys_FileRead
      (JNIEnv *, jclass, jint, jint);
    
    /*
    * Class:com_meijin_dict_reader_FileSys
    * Method:   FileWrite
    * Signature: (I[BI)I
    */
    JNIEXPORT jintJNICALL Java_com_meijin_dict_reader_FileSys_FileWrite
      (JNIEnv *, jclass, jint, jbyteArray, jint);
    
    /*
    * Class:com_meijin_dict_reader_FileSys
    * Method:   FileClose
    * Signature: (I)I
    */
    JNIEXPORT jintJNICALL Java_com_meijin_dict_reader_FileSys_FileClose
      (JNIEnv *, jclass, jint);
    
    #ifdef __cplusplus
    }
    #endif
    #endif

其中JNIEXPORT和JNICALL两个宏是JNI的关键字,表示该函数需要被JNI调用,而jint,jstring,jbyteArray是以JNI为中介使JAVA中对应类型与本地类型对接的类型,jobject为需要返回的java对象,类型对应表如下:

7、实现本地方法调用接口

根据对应的.h文件实现其接口。
JNI_FileSys.c代码:

#include"JNI_FileSys.h"
    #define LOG_TAG"JNI_FileSys"
    #define  LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
    #define  LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
    #include<android/log.h>
    #include"FileSys.h"
    
    /*
    * Class:com_luoxudong_jni_reader_FileSys
    * Method:   FileOpen
    * Signature: ([BI)I
    */
    JNIEXPORT jintJNICALL Java_com_luoxudong_jni_reader_FileSys_FileOpen
      (JNIEnv *env, jclass jobj, jstring pFileName,jint openMode)
    {
      UINT8 *pbyFileName = (UINT8*)(*env)->GetStringUTFChars(env, pFileName, 0);
      LOGI("file name:%s---opentype:%d", pbyFileName, openMode);
      return FileOpen(pbyFileName,openMode);
    
    }
    
    /*
    * Class:com_luoxudong_jni_reader_FileSys
    * Method:   FileLength
    * Signature: (I)I
    */
    JNIEXPORT jintJNICALL Java_com_luoxudong_jni_reader_FileSys_FileLength
      (JNIEnv *env, jclass jobj, jint fd)
    {
      return FileLength(fd);
    }
    
    /*
    * Class:com_luoxudong_jni_reader_FileSys
    * Method:   FileSeek
    * Signature: (III)I
    */
    JNIEXPORT jintJNICALL Java_com_luoxudong_jni_reader_FileSys_FileSeek
      (JNIEnv *env, jclass jobj, jint fd, jintoffset, jint origin)
    {
    
      return FileSeek(fd, offset,origin);
    }
    
    /*
    * Class:com_luoxudong_jni_reader_FileSys
    * Method:   FileRead
    * Signature:(II)Lcom/luoxudong/jni/bean/CusBuffer;
    */
    JNIEXPORT jobjectJNICALL Java_com_luoxudong_jni_reader_FileSys_FileRead
      (JNIEnv *env, jclass jobj, jint fd, jintcount)
    {
      int nReadLen = 0;
      UINT8 *pBuf = (UINT8*)malloc(count);
      memset(pBuf, 0, count);
    
      nReadLen = FileRead(fd, pBuf,count);
    
      jbyte *pBy = (jbyte *)pBuf;
      jbyteArray jarray =(*env)->NewByteArray(env, nReadLen);
      (*env)->SetByteArrayRegion(env,jarray, 0, nReadLen, pBy);  
      jclassm_cls = (*env)->FindClass(env,"com/luoxudong/jni/bean/CusBuffer");
      jmethodID m_mid =(*env)->GetMethodID(env, m_cls, "<init>", "()V");
      jfieldID  m_fid1 = (*env)->GetFieldID(env, m_cls,"buffer", "[B");
      jfieldID  m_fid2 = (*env)->GetFieldID(env, m_cls,"nBufferLen", "I");
    
      jobject   m_obj = (*env)->NewObject(env, m_cls,m_mid);
      (*env)->SetObjectField(env,m_obj, m_fid1, jarray);
      (*env)->SetIntField(env, m_obj,m_fid2, nReadLen);
      return m_obj;
    }
    
    /*
    * Class:com_luoxudong_jni_reader_FileSys
    * Method:   FileWrite
    * Signature: (I[BI)I
    */
    JNIEXPORT jintJNICALL Java_com_luoxudong_jni_reader_FileSys_FileWrite
      (JNIEnv *env, jclass jobj, jint fd,jbyteArray buf, jint count)
    {
      jbyte *pjb = (jbyte*)(*env)->GetByteArrayElements(env, buf, 0);
      jsize len =(*env)->GetArrayLength(env, buf);
      UINT8 *byBuf = (UINT8 *)pjb;
      pjb[len] = '\0';
      return FileWrite(fd, byBuf,count);
    }
    
    /*
    * Class:com_luoxudong_jni_reader_FileSys
    * Method:   FileClose
    * Signature: (I)I
    */
    JNIEXPORT jintJNICALL Java_com_luoxudong_jni_reader_FileSys_FileClose
      (JNIEnv *env, jclass jobj, jint fd)
    {
      return FileClose(fd);
    }

其中头部定义了些andriod中日志输出所需要的宏,以及其他关联的.h文件,在一些地方C跟C++的使用语法不太一样,如在C中调用UINT8 pbyFileName = (UINT8)(*env)->GetStringUTFChars(env, pFileName, 0),
而C++中的语法为env-> (UINT8 *)GetStringUTFChars(pFileName,0)。

8、生成共享库

把编写好的各种相关联代码放在一个文件夹中,编写android.mk文件,使用ndk生成libJNI_FileSys.so文件。

会在libs\armeabi目录下生成.so文件

9、应用程序调用

把生成好的libJNI_FileSys.so文件放入java工程的libs目录下,就可以使用了


10、应用程序调用

当然在android下读写文件时还需要配置权限

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

10、运行效果

附上完整源代码: android JNI调用-文件操作

转载请指明出处:http://www.luoxudong.com/?p=1

有88人对 “Android中JNI调用–文件操作”留言了

  1. This website was… how do you say it? Relevant!!
    Finally I’ve found something which helped me.
    Thanks!

  2. An interesting discussion is definitely worth comment.
    I do think that you should publish more about this subject, it may not be a taboo subject
    but usually people do not discuss such subjects. To the next!
    All the best!!

  3. It’s an awesome article designed for all the online visitors; they will obtain advantage from it I am sure.

  4. Thanks for the marvelous posting! I truly enjoyed reading
    it, you may be a great author. I will make certain to bookmark your blog
    and will come back down the road. I want to encourage you continue your great posts, have a nice weekend!

  5. I have read so many posts on the topic of the blogger lovers but this paragraph is actually a nice post, keep it up.

  6. It’s the best time to make some plans for the future and it’s time to be happy.
    I have read this post and if I could I want to suggest you few interesting things or tips.
    Perhaps you can write next articles referring to this article.

    I want to read more things about it!

  7. My brother recommended I may like this web site. He was once totally right.
    This publish actually made my day. You cann’t imagine simply how much time I had spent for this
    info! Thank you!

  8. I am really enjoying the theme/design of your site.

    Do you ever run into any browser compatibility problems?
    A couple of my blog audience have complained about my blog not working correctly in Explorer but looks great in Opera.

    Do you have any suggestions to help fix this issue?

  9. Hi, always i used to check website posts here in the early hours in the morning, as i love to gain knowledge of more and more.

  10. It is actually a nice and helpful piece of information. I
    am happy that you just shared this helpful information with us.
    Please stay us up to date like this. Thanks for sharing.

  11. If some one wishes expert view regarding running a blog afterward i recommend him/her to go to see this web site, Keep up the fastidious
    work.

  12. Hi there! Do you know if they make any plugins to assist with Search Engine Optimization? I’m trying to get
    my blog to rank for some targeted keywords but I’m not seeing very good success.

    If you know of any please share. Thanks!

  13. Hello to every body, it’s my first visit of this weblog; this weblog carries awesome
    and in fact fine stuff for visitors.

  14. Nice post. I learn something new and challenging on websites I stumbleupon on a daily basis.

    It will always be useful to read through content from other writers and use something from their web sites.

  15. Right away I am going to do my breakfast, after having my breakfast coming yet again to read other news.

  16. I have read several good stuff here. Certainly value bookmarking for revisiting.
    I surprise how a lot attempt you put to create one of these fantastic
    informative web site.

  17. Great blog here! Also your web site loads up very fast! What
    web host are you using? Can I get your affiliate link
    to your host? I wish my site loaded up as quickly as yours
    lol

  18. What’s up mates, how is the whole thing, and what you would like to say concerning this paragraph, in my view its really amazing in support of me.

  19. I don’t even know how I ended up here, but I thought this post was good.
    I do not know who you are but definitely you’re going to a famous blogger if you aren’t already 😉 Cheers!

  20. Hello! I just want to offer you a big thumbs up for your excellent information you’ve got
    right here on this post. I am returning to your blog for more soon.

  21. Excellent post. I was checking continuously this blog and I’m
    impressed! Extremely helpful info specially the last part
    🙂 I care for such information a lot. I was seeking this particular
    information for a long time. Thank you and good luck.

  22. Hello Dear, are you in fact visiting this site regularly,
    if so then you will definitely take fastidious experience.

  23. What a information of un-ambiguity and preserveness of valuable experience on the
    topic of unpredicted feelings.

  24. My spouse and I stumbled over here by a different web address and thought I might check things out.
    I like what I see so i am just following you. Look forward
    to checking out your web page again.

  25. hi!,I love your writing very a lot! share we keep in touch extra about your article on AOL?

    I require a specialist in this area to solve my problem. Maybe
    that’s you! Taking a look forward to peer you.

  26. Please let me know if you’re looking for a article author for your blog.
    You have some really good articles and I feel I would be a good asset.
    If you ever want to take some of the load off, I’d really like to write
    some material for your blog in exchange for a link back to mine.
    Please send me an email if interested. Thanks!

发表评论

邮箱地址不会被公开。