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語言形式接口函數      

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


                 

     Java代碼爲:

[java] view plain copy
  1. package cn.jna.test;  
  2.   
  3.   
  4. import com.sun.jna.Library;  
  5. import com.sun.jna.Native;  
  6.   
  7. public interface CFJna extends Library {  
  8.   
  9.     //加載動態資源庫  
  10.     CFJna library = (CFJna) Native.loadLibrary("TestCF", CFJna.class);//注意庫名稱的寫法不要含有lib字符  
  11.       
  12.     //定義要調用的方法,與cf.h頭文件中定義的函數名一樣  
  13.     int TestReadCF();  
  14. }  

          4. 測試調用,如下圖:


               java 代碼:

[java] view plain copy
  1. package cn.jna.test;  
  2.   
  3. public class CFJnaTest {  
  4.   
  5.     public static void main(String[] args) {  
  6.   
  7.         int testReadCF = CFJna.library.TestReadCF();  
  8.         System.out.println("testReadCF:"+testReadCF);  
  9.     }  
  10.   
  11. }  
文章 轉載:  Java 調用 C/C++ 之 JNA 系列實戰篇 —— 起步 (一)


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