linux中java通过jni调用so动态库中的方法

项目中需要调用so动态库中的方法来实现需要的功能,所以需要在java项目中通过jni的方式实现调用。

本次学习记录所对应的场景为:

  1. 已经有so库和对应方法的头文件提供。
  2. 项目提供的so和头文件不是jni的头文件,所以需要自己通过提供的头文件,编写jni方法,然后重新编译一个so文件,然后再把两个so同时加载。(刚开始接触,不知道能不能在没有源码的情况下把两个so编译合并为一个so,这样就不用加载两个了,不过这个想法暂时还没有去了解。)

 

1. 确保gcc编译器已安装
2. 编写FileUtil.java 代码,用native声明需要用c实现的函数。
如果源程序是包含在package的话,应该建立同样的文件夹结构,如com/hnrbyl/rmas/util/FileUtil.java

Java代码 


  
public class FileUtil {  
    public native static String ResultText();   
    public static void main(String[] args) {  
        System.loadLibrary("FileUtil");  
        String s=FileUtil.ResultText();  
        System.out.println(s);  
    }  
  
}  


项目中的代码:

Java代码 

public class FileUtil {    
        //要调用.so中的方法    
    public native static String ResultText(String txtPath, String pdfPath);     
    
    public static String autoAnalyse(String txtPath, String pdfPath){    
        //加载自动分析已上传心电图的动态链接库文件    
        System.loadLibrary("FileUtil");    
        String jsonData = FileUtil.ResultText(txtPath, pdfPath);    
        return jsonData;    
    }    
}   

3. 在FileUtil.java文件所在目录下编译.java文件
Javac FileUtil.java

4. 编译第三步生成的.class文件,生成对应的.h头文件,本例中生成com_hnrbyl_rmas_util_FileUtil
Javah –classpath  ~workspace\elect\WebRoot\WEB-INF\classes -d d:\ -jni com.hnrbyl.rmas.util.FileUtil

其中java中各个命令的意思
-classpath <路径> 用于转入类的路径
-d <目录> 输出目录
-jni 生成JNI样式的头文件(默认)

这个Java文件是在路径“E:\workspace\elect\src”下,包“package com.hnrbyl.rmas.util;”中的
得到的FileUtil 对应的class文件,在路径“E:\workspace\elect\WebRoot\WEB-INF\classes\com\hnrbyl\rmas\util”下。

注意到以上我们命令中指定的路径
注意到我们的命令符的执行位置是源代码目录” E:\workspace\elect\src\”
-classpath  后面的路径是指包” com.hnrbyl.rmas.util”所在的根路径

 

5. 第四部中生成的头文件内容

C代码

/* DO NOT EDIT THIS FILE - it is machine generated */  
#include "jni.h"  
/* Header for class FileUtil */  
  
#ifndef _Included_com_hnrbyl_rmas_util_FileUtil  
#define _Included_com_hnrbyl_rmas_util_FileUtil  
#ifdef __cplusplus  
extern "C" {  
#endif  
/* 
 * Class:     com_hnrbyl_rmas_util_FileUtil 
 * Method:    ResultText 
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 
 */  
JNIEXPORT jstring JNICALL Java_com_hnrbyl_rmas_util_FileUtil_ResultText  
  (JNIEnv *, jclass, jstring, jstring);  
  
  
#ifdef __cplusplus  
}  
#endif  
#endif  

6. 编写FileUtil.c文件,实现引用第4步中生成的.h头文件,并声明其中的方法。

#include "stdlib.h"  
#include "stdio.h"  
#include "FileUtil.h"  
#include "dlfcn.h"  
#include "jni.h"  
JNIEXPORT jstring JNICALL  Java_com_hnrbyl_rmas_util_FileUtil_ResultText  
  (JNIEnv *env, jobject obj, jstring txtPath, jstring pdfPath)   
    {  
       char** (*myso)(char* a, char* b);//function pointer     
       void *handle;   
       char *errorInfo;  
       handle=dlopen("libauto_analyse.so",RTLD_LAZY);//open lib file     
       errorInfo = dlerror();  
       // 如果返回 NULL 句柄,表示无法找到对象文件,过程结束。否则的话,将会得到对象的一个句柄,可以进一步询问对象  
       if (errorInfo){  
           // 如果返回 NULL 句柄,通过dlerror方法可以取得无法访问对象的原因  
           printf("Open Error:%s.\n",dlerror());  
           return 0;  
       }  
       // 使用 dlsym 函数,尝试解析新打开的对象文件中的符号。您将会得到一个有效的指向该符号的指针,或者是得到一个 NULL 并返回一个错误  
       myso=dlsym(handle,"auto_analyse");//call dlsym function    
       errorInfo = dlerror();// 调用dlerror方法,返回错误信息的同时,内存中的错误信息被清空        
       if (errorInfo){  
           printf("Dlsym Error:%s.\n",errorInfo);  
           return 1;  
       }  
       char* a=(*env)->GetStringUTFChars(env, txtPath, 0);  
       char* b=(*env)->GetStringUTFChars(env, pdfPath, 0);  
       char **str=(*myso)(a,b);     
       dlclose(handle);    
       (*env)->ReleaseStringUTFChars(env, txtPath, a);  
       (*env)->ReleaseStringUTFChars(env, pdfPath, b);  
       jstring rtn;  
       rtn = (*env)->NewStringUTF(env,str[1]);  
       return rtn;  
    }  

 

7. 讲第6步中编写的FileUtil.c文件,编译成.so文件

gcc -I/wenjin/jdk1.7.0_25/include/ -I/wenjin/jdk1.7.0_25/include/linux/ -fPIC -shared -o libFileUtil.so FileUtil.c  -L. -lefsapi -Wl,-rpath,.

注:/ wenjin/jdk1.7.0_25/include 是jni.h头文件所在的路径

/ wenjin/jdk1.7.0_25/include/linux 是jni_md.h所在的路径

-L.  当前目录下,项目需要链接的so库文件,也就是编写so需要用到的 别的so。需要在编译的时候指定。

GCC常用参数详解https://www.cnblogs.com/zhangsir6/articles/2956798.html

8. 将第7步中生成的libFileUtil.so文件拷贝到java的加载库LD_LIBRARY_PATH指向的路径中。

9.然后就可以通过system.loadlibrary加载so,然后调用函数了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值