Java 調用 C/C++ 之 JNA 系列實戰篇 —— 起步 (一)

一、爲什麼要寫這篇文章         

        最近單位開發一些項目,要用到Java 調用 C/C++ 動態鏈接庫,我採了JNA的調用方式,同時在開發過程中遇到過一些問題,但上網查找,發現對JNA的介紹不多,大部分只是一個初級入門,所以結合自己的實際開發,把總結出來的知識點及問題與大家分享下。在Windows 平臺與 Linux平臺都實現了。


二、爲什麼選用JNA

       Java 調用 C/C++ 動態鏈接庫,有兩種方式 JNI 與 JNA,它們的原理一樣,但使用起來難易度卻有區別,做個對比:

      1. JNI 比JNA難度要高一些,因爲JNI要根據Java代碼生成頭文件,生成特殊的方法簽名。再針對頭文件定義的函數,用JNI 語法結合C/C++語法來實現函數,在函數中再去調用動態鏈接庫,在這個過程中還需要去管理內存的問題(有一篇文章給大家推薦下:在 JNI 編程中避免內存泄漏)。而JNA方式完全省略了這一複雜過程。使用方便是JNA的一大特點。

         2. JNI 可以實現Java 調用 C/C++,同時 C/C++也可調用Java 。但JAN卻只能Java 調用 C/C++,不具備反向調用。剛好在項目中不要用到C/C++調用JAVA,所以選擇了JNA的方式。


三、 環境申明

          環境沒有配好,會出現許多錯誤,如:找不到庫文件,無法加載庫文件等等,如果是剛上手,一時會找不到出錯點。

我實際項目中用到的環境是(已經設置好了jdk的環境,另外在Linux平臺上還要加設一變量LD_LIBRARY_PATH,它的值要等於你即將調用的so文件存放的目錄,我習慣把so文件存在我的項目直接目錄下,路徑也就指向項目目錄):

      1. windows (64位), JDK (64位),dll文件 (64位)

      2. Linux (64位),      JDK (64位),so文件 (64位)

      我的意思是要用 64位的JDK去調用64位的dll/so 文件; 32位的JDK去調用32位的dll/so 文件,如果不對應則會生如下異常信息:

      異常一:如在windows平臺,用64位jdk 調用 32位的dll :Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'XxxEngine': Native library (win32-  x86-64/XxxEngine.dll) not found in resource path,它是意思是沒有找到64位的dll文件,它需要的是64的文件。

      異常二:我在Linux平臺上還發現有這樣一個異常:Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'XxxEngine': Native library (linux-x86-64/libKwsEngine.so) not found in resource path,而我已經保證了64位的JDK調用64位的so 文件,並且Linux也是64位的操作系統,經過一番查找,是因爲libXxxEngine.so文件內部引用了另外的so文件,把的依賴的文件加入就可以解決問題了,如放在/usr/local/lib 下面,此爲系統默認查找庫資源的路徑。如何查看一個so文件依賴其它的文件方式是:ldd libXxxEngine.so。如果確定環境不再有問題,也執行過ldconfig命令,則重新啓動下電腦試試。


三、官方JNA

      JNA的官方資源路徑爲https://github.com/twall/jna/,在這裏可以下載 jna.jar 文件,以及可以查看文檔JavaDoc,開發時一定要查看文檔,因以它裏面介紹了C Type 對應到 Java Type 數據類型。如下圖



四、開發結構

        1.  把需要調用的dll/so文件放到項目的根目錄下,如下圖在linux環境下面libTestCF.so (在linux 下面要設置環境變量:LD_LIBRARY_PATH=/root/workspace/HelloJNA , Windows下面不用設置此環境變量),在linux下的文件爲libTestCF.so,在windows下面爲TestCF.dll

         

         

       2. 在libTestCF.so有要被調用的函數,在cf.h頭文件有如下申明:採用C語言形式接口函數      

extern "C"
{
	Public  int TestReadCF();
}
      3. 根據頭文件編寫Java代碼:如圖


                

     Java代碼爲:

package cn.jna.test;


import com.sun.jna.Library;
import com.sun.jna.Native;

public interface CFJna extends Library {

	//加載動態資源庫
	CFJna library = (CFJna) Native.loadLibrary("TestCF", CFJna.class);//注意庫名稱的寫法不要含有lib字符
	
	//定義要調用的方法,與cf.h頭文件中定義的函數名一樣
	int TestReadCF();
}

          4. 測試調用,如下圖:


               java 代碼:

package cn.jna.test;

public class CFJnaTest {

	public static void main(String[] args) {

		int testReadCF = CFJna.library.TestReadCF();
		System.out.println("testReadCF:"+testReadCF);
	}

}

 收尾 JNA調用還是很方便上手的, 在接下來的文章我將會把我實際開發中應用到的知識與 大家分享,請繼續關注,或關注我的新浪微博:微博Abel




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章