Java调用so文件[通俗易懂]

Java调用so文件[通俗易懂]公司的硬件让我帮忙调用一个so文件,想着一直都没机会自己写一个jni,于是就答应了,在调用的过程中还踩了不少坑,特地写一篇博客记录一下。一、使用技术原本是想直接用java自带的jni,但是我们硬件只给了一个so文件,而且里面的函数命名等规则不符合java的jni调用标准,于是就打算使用框架jna来调用。JNA就是建立在JNI之上,它简化了Java调用原生函数的过程。JNA提供了一…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

 


公司的硬件让我帮忙调用一个so文件,想着一直都没机会自己写一个jni,于是就答应了,在调用的过程中还踩了不少坑,特地写一篇博客记录一下。


一、使用技术

原本是想直接用java自带的jni,但是我们硬件只给了一个so文件,而且里面的函数命名等规则不符合java的jni调用标准,于是就打算使用框架jna来调用。

JNA就是建立在JNI之上,它简化了Java调用原生函数的过程。JNA提供了一个动态的C语言编写的转发器(实际上也是一个动态链接库)可以自动实现Java与C之间的数据类型映射。从性能上会比JNI技术调用动态链接库要低,但开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射,大大降低了Java调用本体共享库的开发难度。

二、编码前准备

2.1 首先将so文件放在项目resource文件夹下:

Java调用so文件[通俗易懂]

之所以放在该目录下,是为了方便编码过程中能动态获得该文件的路径,其实so文件可以放在任意路径下,只需在加载该so文件的时候,传入的文件的路径给加载器即可。

2.2 引入jna的jar包

有两种引入方式:

一、直接在网上下载jna-3.0.9.jar,然后手动引入jar包

二、在pom.xml中引入[仅限maven项目]

    <dependency>
        <groupId>com.sun.jna</groupId>
        <artifactId>jna</artifactId>
        <version>3.0.9</version>
    </dependency>

ps: 有一个地方需要注意一下,如果你用的是idea,在jar包引入后可能还是会出现ClassNotFoundException,这个时候可以参考以下步骤:

Java调用so文件[通俗易懂]

完成上述步骤即可解决该异常


三、开始编码

 3.1准备一个类,用于解析so文件

package com.appcups.energy.chargingstation.server.chargingstationsysapi.jna;

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

//继承Library,用于加载库文件
public interface Clibrary extends Library {

    // [Native.synchronizedLibrary] 阻止多线程同时访问本地代码
    Clibrary INSTANTCE = (Clibrary) Native.synchronizedLibrary(
            (Clibrary) Native.loadLibrary(
                    Clibrary.class.getResource("/secret_udp.so")
                        .getPath()
                        .substring(1)// substring(1)的原因是在Windows下获取到的路径前面会多一个斜杠,但在Linux下不会
                    , Clibrary.class
            )
    );

    // 此方法为so文件中的c语言函数1 -> int test_return_C(void);
    //  ##备注: 这里的void代表无参
    int test_return_C();

    // 此方法为so库中的c语言函数2 -> char* Decrpyt( char * input);
    // ## 备注: 这里的char* 是c语言中的指针,与java中的String相对应
    String Decrpyt(String input);
    
}

注: 对于so文件中c类型与java类型的映射关系,可以参考下图:

Java调用so文件[通俗易懂]

Java调用so文件[通俗易懂]


3.2 编写测试类

public class Demo {

    public static void main(String[] args) {
        Clibrary instance = Clibrary.INSTANTCE;
        // 方法一
        int result = instance.test_return_C();
        
        // 方法二
        String arr = instance.Decrpyt("方法二参数");
    }

}

测试完毕,可以将函数调用返回值打印到控制台,查看调用结果

四、将项目部署到Linux

    我将项目直接部署到Linux是无法正常运行的,需要修改 Clibrary.java 类,因为Linux下使用getResource()方法获取到的路径是正确的,只有在Windows上调用getResource()方法才会多出一条斜杠,所以在Linux下需要将类中的.subString(1)方法的调用删掉,为了让代码兼容Windows和Linux操作系统,我将Clibrary.java 类修改为以下代码:

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

//继承Library,用于加载库文件
public interface Clibrary extends Library {
    String os = System.getProperty("os.name");  // 获取当前操作系统的类型
    int beginIndex = os != null && os.startsWith("Windows") ? 1 : 0;// windows操作系统为1 否则为0

    Clibrary INSTANTCE = (Clibrary) Native.synchronizedLibrary(
            (Clibrary) Native.loadLibrary(
                    Clibrary.class.getResource("/secret_udp.so")
                            .getPath()
                            .substring(beginIndex)
                    , Clibrary.class
            )
    );

    // 此方法为so文件中的c语言函数1 -> int test_return_C(void);
    //  ##备注: 这里的void代表无参
    int test_return_C();

    // 此方法为so库中的c语言函数2 -> char* Decrpyt( char * input);
    // ## 备注: 这里的char* 是c语言中的指针,与java中的String相对应
    String Decrpyt(String input);

}

代码通过获取当前系统的操作类型来改变调用substring的作用域,实现了兼容性。

但在代码运行时,还是报错了:

Java调用so文件[通俗易懂]

参考王小草的博客,发现在Windows下生成的so文件是无法在Linux上运行的,因为不同系统生成的文件的ELF header可能是不一样的,所以让硬件工程师在Linux下重新生成了一个so文件,发现竟然真的没有报错了

写在最后: 如需转载,请注明出处,如有问题,欢迎在评论区留言.

 

====== 2020-06-19 ======

网上有人遇到这样的报错:java.lang.UnsatisfiedLinkError: Unable to load library ‘lib/HCNetSDK’: ÕҲ»µ½ָ¶;我无法复现。。能不能有人分享个so文件给我,我调试一下,给百度云链接或者csdn下载链接都行

这个问题博主解决不了 大家可以参考:https://www.cnblogs.com/xdk1002/p/13218980.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/191785.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • vivo21a点击android版本,vivoX21适配安卓P系统

    许多小伙伴们应该都是知道最近即将推出的AndroidP系统吧,这个系统十分的强大,如果你使用的是vivoX21那么你就有福利了,你可以使用vivoX21AndroidP升级这个系统。AndroidPbeta是vivoX21适配安卓P系统的一个好的系统,你可以使用vivoX21AndroidP对自己的手机进行全面性的升级,让你的手机跟上步伐,走的更靠前!vivoX21Android…

    2022年4月8日
    280
  • PHP中exit,exit(0),exit(1),exit(‘0’),exit(‘1’),die,return的区别

    PHP中exit,exit(0),exit(1),exit(‘0’),exit(‘1’),die,return的区别

    2021年10月22日
    43
  • mac录屏软件推荐_mac 录屏软件

    mac录屏软件推荐_mac 录屏软件工作和生活中,我们常常需要录制电脑屏幕,例如老师和学生上网课、游戏大神分享操作技巧。那么,在Mac上有哪一些好用的录屏软件呢?作为一个工具软件重度爱好者,我整理了以下五大最好用的录屏软件,大家可以自行参考种草:一、FilmageScreenRecorderforMacFilmageScreen是一款简单易操作,功能十分强大的一站式视频软件,集屏幕录制、摄像头录制、音频录制、视频剪辑、视频格式转换为一体,可以说是真正满足你对于视频操作的所有需求。目前是只有Mac端,所以用Mac的童鞋们千万不.

    2022年9月25日
    1
  • 如何在pycharm中进行全局搜索

    如何在pycharm中进行全局搜索使用doubleshift可以在整个项目中搜索含关键字在项目中的位置及关键字在文件中的位置。

    2022年5月15日
    54
  • SQL Server2000安全设置内容

    SQL Server2000安全设置内容

    2021年4月27日
    143
  • 波束形成

    波束形成1.问题描述:数字波束形成器是全数字化超声成像的基础,也是高性能彩超的保证。数字波束形成包括发射和接收两个部分。数字是接收波束形成的关键技术,它通过使用顺序储存器FIFO或随机存取存储器双端口RAM替代模拟式波束形成器中的LC延时线来实现波束聚焦,即以数字延时补偿替代模拟延时的补偿。数字延时不仅能实现精确延时补偿,实现所谓的逐点跟踪式动态聚焦,还能方便实现动态孔径、动态变迹控制,克服模拟式延时补偿存在的诸多固有缺点,通道数增加不受限制,是图像品质得以全面提高。2.部分程序:close..

    2022年6月15日
    39

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号