Java 調c/c++ so庫中接口

1、vs2013 新建win32 dll 空項目,main.h :

  1. extern "C" _declspec(dllexport) void hello();  
  2. extern "C" _declspec(dllexport) int add(int first, int second);  

2、main.cpp,然後生成dll文件

  1. #include "main.h"  
  2. #include <iostream>  
  3.   
  4. int add(int a, int b){  
  5.     return a + b;  
  6. }  
  7.   
  8. void hello()  
  9. {  
  10.     printf("Hello World!\n");  
  11. }  

3、eclipse 新建 java項目,把之前生成好的dll文件放在項目根目錄,新建包、類,HelloWorld.java : 

  1. package com.busymonkey;  
  2.   
  3. import com.sun.jna.Library;  
  4. import com.sun.jna.Native;  
  5.   
  6. public class HelloWorld {  
  7.   
  8.     public interface TestDll1 extends Library {  
  9.         TestDll1 INSTANCE = (TestDll1) Native.loadLibrary("javaJNA", TestDll1.class);  
  10.         public int add(int a, int b);    
  11.         public void hello();  
  12.     }  
  13.   
  14.     public static void main(String[] args) {  
  15.         System.out.println(TestDll1.INSTANCE.add(1,2));  
  16.         TestDll1.INSTANCE.hello();  
  17.     }  
  18. }  

項目添加 jna 的 jar 包:

上面是windows環境下java程序調用dll,以下是linxu環境 java程序調用so動態庫:

1、新建一個main.cpp:(這裏需要注意的是外部聲明,不然找不到動態庫中的函數)

  1. #include <stdlib.h>    
  2. #include <iostream>    
  3. using namespace std;    
  4.     
  5. extern "C"    
  6. {    
  7.     void test() {    
  8.          cout << "TEST" << endl;    
  9.     }    
  10.     
  11.     int addTest(int a,int b)    
  12.     {    
  13.       int c = a + b ;    
  14.       return c ;    
  15.     }     
  16. }  

 

注:學過C/C++(cplusplus/cpp)的人都知道,extern是編程語言中的一種屬性,它表徵了變量、函數等類型的作用域(可見性)屬性,是編程語言中的關鍵字。當進行編譯時,該關鍵字告訴編譯器它所聲明的函數和變量等可以在本模塊或者文件以及其他模塊或文件中使用。通常,程序員都只是在“*h”(頭文件)使用該關鍵字以限定變量或函數等類型的屬性,然後在其他模塊或本模塊中使用。

 

 

2、編譯so動態庫文件(這裏注意,linux掃描lib開頭的so文件,但之後java程序中加載的時候不需要lib開頭,也不需要.so後綴):

  1. g++ -fpic -shared -o libtest.so main.cpp  


爲了之後的  java  程序能找到該動態庫文件,加一下環境變量,並且 source 一下:

  1. #vim /etc/profile  
  2. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$/opt/javaJNA  

3、HelloWorld.java :

  1. import com.sun.jna.Library;  
  2. import com.sun.jna.Native;  
  3.   
  4. public class HelloWorld {  
  5.   
  6.         public interface TestDll1 extends Library {  
  7.                 TestDll1 INSTANCE = (TestDll1) Native.loadLibrary("test", TestDll1.class);  
  8.                 void test();  
  9.                 int addTest(int a, int b);  
  10.         }  
  11.   
  12.         public static void main(String[] args) {  
  13.                 TestDll1.INSTANCE.test();  
  14.                 int c = TestDll1.INSTANCE.addTest(10, 20);  
  15.                 System.out.println(c);  
  16.         }  
  17. }  


同樣在目錄下拷貝好  jna  的  jar  包,然後編譯生成:

  1. javac -classpath jna-3.5.1.jar HelloWorld.java  

4、運行程序:

  1. java -classpath .:jna-3.5.1.jar HelloWorld 

5、結果:

 

真實項目代碼

1.導包

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>4.1.0</version>
</dependency>

2.將.so文件放入/usr/lib目錄下

3.編寫接口調用

package com.unv.yncms.service.cds;
import com.sun.jna.*;
import com.sun.jna.ptr.IntByReference;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class CDSService {
    public interface CDSLibC extends Library {
        CDSLibC cds = (CDSLibC) Native.loadLibrary("cds_libc", CDSLibC.class);

        int CDS_Init(int a, CDSCfg.ByReference cdsCfg);

        void CDS_Destroy();  //CDS銷燬函數

        /*圖片讀取*/
        int CDS_ReadOnceEx(String fullFile, long offset, long len, Pointer buf);

    }

    public static class CDSCfg extends Structure {
        public static class ByReference extends CDSCfg implements Structure.ByReference {
        }

        public static class ByValue extends CDSCfg implements Structure.ByValue {
        }

        public interface fp extends Callback {
            void invoke(String filename);
        }

        /**
         * * < Metadata ip地址信息  char
         */
        public byte[] szMetaDataAddr = new byte[64];
        /**
         * * < Metadata port
         */
        public short usMetaDataPort;
        /**
         * * < 數據庫連接數
         */
        public int ulDBConnCount;
        /**
         * * < 一個Md能管理的最大nd個數,默認1000
         */
        public int ulMdMaxNdNum;
        /**
         * * < Nd編碼
         */
        public byte[] szNdCode = new byte[48];
        /**
         * * < ND ip地址信息
         */
        public byte[] szNDAddr = new byte[64];
        /**
         * * < ND port
         */
        public short usNDPort;
        /**
         * * < RR port
         */
        public short usRRPort;

        /**
         * * < 單個資源的最大長度,最大8T
         */
        public int ulMaxResLen;
        /**
         * * < 一個客戶端最多併發任務數
         */
        public int ulMaxClientTaskNum;
        /**
         * * < 一個Nodedata最多併發任務數
         */
        public int ulMaxNDTaskNum;
        /**
         * * < 一個Nodedata最大資源個數
         */
        public int ulMaxNDResNum;
        /**
         * * < 客戶端存儲模式,0-帶外,1-帶內
         */
        public int ulClientStoreMode;
        /**
         * * < MFS客戶端存儲模式,0-帶外,1-帶內
         */
        public int ulMFSCliStoreMode;
        /**
         * * < 讀打開選項,參見MAS_CONFIG_FLAGS_E
         */
        public int lReadFlags;
        /**
         * * < 寫打開選項,參見MAS_CONFIG_FLAGS_E
         */
        public int lWriteFlags;
        /**
         * * < 每次讀取字節數,最小64K
         */
        public int ulReadBytesAtTime;
        /**
         * * < 每次寫的字節數,最小64K
         */
        public int ulWriteBytesAtTime;
        /**
         * * < 文件數據緩存大小,僅用於卡口圖片緩存,單位KB
         */
        public int ulDataBufSize;

        /**
         * * < Metadata服務使能狀態
         */
        public int ulMdEnable;
        /**
         * * < 資源管理模塊使能狀態
         */
        public int ulMrEnable;
        /**
         * * < RR模塊使能狀態
         */
        public int ulRrEnable;
        /**
         * * < FC模塊使能狀態
         */
        public int ulFcEnable;
        /**
         * * < 本地緩存使用標識,前提是配置了帶內模式
         */
        public int ulLocalEnable;
        /**
         * * < 本地緩存路徑
         */
        public byte[] szLocalPath = new byte[256];
        /**
         * * < 本地緩存類型
         */
        public int ulLocalType;
        /**
         * * < 本地緩存備份路徑
         */
        public byte[] szLocalPathBak = new byte[256];
        /**
         * * < 本地緩存大小,單位MB
         */
        public int ulLocalCap;
        /**
         * * < 文件預分配大小,在打開接口預分配大小爲0時有效
         */
        public int ulPreFileCap;
        /**
         * * < 文件緩存大小,大於任何一個小文件的大小
         */
        public int ulFileCacheCap;
        /**
         * * < 資源配置路徑
         */
        public byte[] szResConfPath = new byte[256];
        /**
         * * < Ext port
         */
        public short usExtPort;
        /**
         * * < Ext ip地址信息
         */
        public byte[] szExtAddr = new byte[64];
        /**
         * * < fuse功能使能狀態
         */
        public int ulFuseEnable;
        /**
         * * < 圖片緩存張數
         */
        public int ulCacheFileNum;
        /**
         * * < 磁盤休眠功能支持標誌位
         */
        public int ulDiskSleepEnable;
        /**
         * * < 自動加載資源使能標誌
         */
        public int ulAutoLoadRes;
        /**
         * * < Md最大目錄個數,默認655360
         */
        public int ulMdMaxDirNum;
        /**
         * * < ND最大下載帶寬
         */
        public int ulNdMaxFdBand;
        /**
         * * < MD最大管理分組個數,默認256
         */
        public int ulMdMaxGroupNum;

        @Override
        protected List getFieldOrder() {
            return Arrays.asList(new String[]{
                    "szMetaDataAddr", "usMetaDataPort", "ulDBConnCount", "ulMdMaxNdNum",
                    "szNdCode", "szNDAddr", "usNDPort", "usRRPort", "ulMaxResLen", "ulMaxClientTaskNum",
                    "ulMaxNDTaskNum", "ulMaxNDResNum", "ulClientStoreMode", "ulMFSCliStoreMode",
                    "lReadFlags", "lWriteFlags", "ulReadBytesAtTime", "ulWriteBytesAtTime",
                    "ulDataBufSize", "ulMdEnable", "ulMrEnable", "ulRrEnable", "ulFcEnable",
                    "ulLocalEnable", "szLocalPath", "ulLocalType", "szLocalPathBak", "ulLocalCap",
                    "ulPreFileCap", "ulFileCacheCap", "szResConfPath", "usExtPort", "szExtAddr",
                    "ulFuseEnable", "ulCacheFileNum", "ulDiskSleepEnable", "ulAutoLoadRes",
                    "ulMdMaxDirNum", "ulNdMaxFdBand", "ulMdMaxGroupNum"
            });
        }
    }

    /*初始化*/
    public static int init(String pcMdAddr, Short userPost) {
        int Ret1;
        CDSCfg.ByReference result = new CDSCfg.ByReference();

        result.usMetaDataPort = userPost;

        result.szMetaDataAddr = pcMdAddr.getBytes();

        Ret1 = CDSLibC.cds.CDS_Init(0, result);  //調用類庫 ,初始化函數

        if (0 != Ret1) {
            System.out.println("!CDS init fail ....");
            return Ret1;
        }
        System.out.println("init successed!");
        return 0;
    }

    public static void destory() {
        CDSLibC.cds.CDS_Destroy();
    }


    /*t圖片讀取,並保存在本地*/
    public static int readPicture(String fullPath) {
        FileOutputStream outputStream = null;

        try {
           /*配置參數*/
           Pointer pointer = Pointer.NULL;  //空指針
            pointer = new Memory(10485760);  //10MB
            int readOnceEx = CDSLibC.cds.CDS_ReadOnceEx(fullPath, 0, 10485760, pointer);
            /*獲取字節數組*/
          byte[] bytes =   pointer.getByteArray(0,10485760);
            if (-1 == readOnceEx) {
                System.out.println("獲取文件失敗...");
            }
             outputStream = new FileOutputStream("/usr/cds/123.jpg");
            /*將上一個循環的字節寫出去*/
                outputStream.flush();
                outputStream.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return 0;
    }

    public static int run(String fullPath) {
        int ret = -1;
        String szCdmIp;
        short usCdmPort;
        //byte[] pBuf;
        szCdmIp = "192.168.1.110";
        usCdmPort = 8000;
        /*初始化*/
        if (0 != init(szCdmIp, usCdmPort)) {
            System.out.println("init fail");
            return -1;
        }
          /*獲取圖片*/
        ret = readPicture(fullPath);
        System.out.println("-------------"+ret);
        if (0 < ret) {
            System.out.println("獲取圖片失敗!!!!");
        }
         /*銷燬*/
        destory();
        return 0;
    }

    public static void main(String[] args) {
        String url = "204.204.116.222:7549/common$3448_74253/FsStorage/IAFS_FACEDB_3/[email protected]?dev=cdvserver&fid=770979-31-514BE80041-0-919D";
        run(url);
    }


}

 

2、Java和C數據類型的對應表如下:

Java 類型

C 類型

原生表現

 Boolean

 int

 32位整數 (可定製)

 byte

 char 

 8位整數

 char

 wchar_t

 平臺依賴

 short

 short

 16位整數

 int

 int

 32位整數

 long

long long, __int64

 64位整數

 float

 float

 32位浮點數

 double

 double

 64位浮點數

 Buffer/Pointer

 pointer

 平臺依賴(32或 64位指針)

 <T>[] (基本類型的數組)

 pointer/array

32或 64位指針(參數/返回值)

鄰接內存(結構體成員)

 String

 char*

/0結束的數組 (native encoding or jna.encoding)

 WString

 wchar_t*

 /0結束的數組(unicode)

 String[]

 char**

 /0結束的數組的數組

 WString[]

 wchar_t**

 /0結束的寬字符數組的數組

 Structure

 struct*/struct

指向結構體的指針 (參數或返回值) (或者明確指定是結構體指針)
結構體(結構體的成員) (或者明確指定是結構體)

 Union

union 

 等同於結構體

 Structure[]

 struct[]

 結構體的數組,鄰接內存

 Callback

 <T> (*fp)()

 Java函數指針或原生函數指針

 NativeMapped

 varies

 依賴於定義

 NativeLong

 long

 平臺依賴(32或64位整數)

 PointerType

 pointer

 和 Pointer相同

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