原理:简而言之就是把jar包中的动态库解压写到系统临时文件目录中去,然后在动态库的目录结构的要求进行加载
获取系统临时文件目录:System.out.println(System.getProperty("java.io.tmpdir"));
// 如果动态库有目录结构方面的要求,就提前判断目录是否存在
public static void main(String[] args) {
String HCNetSDKCom = System.getProperty("java.io.tmpdir") + "HCNetSDKCom";
System.out.println(HCNetSDKCom);
File file = new File(HCNetSDKCom);
if (!file.exists()) {
file.mkdir();
}
}
【DynamicParseUtil】
package com.netsdk.lib.utils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
/**
* 动态解析库
*/
public class DynamicParseUtil {
private DynamicLibParseHandler handler;
private SAXParserFactory saxParserFactory;
private SAXParser saxParser;
/**
* 适配各系统动态库名称大小写不同,以及lib前缀造成的找不到库的问题
*
* @param currentSystem 当前系统:win64,win32,linux64,linux32,mac64
* @param libName 动态库名称
* @return
*/
public String compareLibName(String currentSystem, String libName) {
String dynamicLibName = libName;
List<String> libs = handler.getLibsBySystem(currentSystem);
if (currentSystem.equalsIgnoreCase("win64")) {
return findLibs(libs, libName);
}
if (libName.startsWith("lib")) {
dynamicLibName = libName.substring(3);
}
return findLibs(libs, dynamicLibName);
}
private String findLibs(List<String> libs, String libName) {
for (String lib : libs) {
if (libName.equalsIgnoreCase(lib)) {
return lib;
}
}
return "";
}
public List<String> getLibsSystem(String system) {
return handler.getLibsBySystem(system);
}
private DynamicParseUtil() throws ParserConfigurationException {
// 获取SAX分析器的工厂实例,专门负责创建SAXParser分析器
saxParserFactory = SAXParserFactory.newInstance();
// 获取SAXParser分析器的实例
try {
saxParser = saxParserFactory.newSAXParser();
handler = new DynamicLibParseHandler();
} catch (ParserConfigurationException | SAXException e) {
throw new ParserConfigurationException();
}
}
public DynamicParseUtil(InputStream inputSteam)
throws ParserConfigurationException, IOException, SAXException {
this();
saxParser.parse(inputSteam, handler);
}
/** xml解析handler */
private static class DynamicLibParseHandler extends DefaultHandler {
private final HashMap<String, List<String>> dynamics = new HashMap<>();
private final List<String> systems = Arrays.asList("win64", "win32", "linux64", "linux32", "mac64", "linuxARM");
private String currentDynamicSystem;
private List<String> libs;
public List<String> getLibsBySystem(String system) {
return dynamics.get(system);
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
super.startElement(uri, localName, qName, attributes);
if (systems.contains(qName)) {
currentDynamicSystem = qName;
if (libs == null) {
libs = new ArrayList<>();
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if (systems.contains(qName)) {
// 保存到hashmap中
dynamics.put(currentDynamicSystem, libs);
// 清除libs
libs = null;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
String lib = new String(ch, start, length);
if (!lib.trim().isEmpty()) {
libs.add(lib);
}
}
}
}
【LibraryLoad】
package com.jt.hk.utils;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
/**
* @description 动态库加载
*/
public class LibraryLoad {
private static final String ARCH_WINDOWS = "win";
private static final String ARCH_LINUX = "linux";
private static final String ARCH_MAC = "mac";
private static final int PREFIX_64 = 64;
private static final int PREFIX_32 = 32;
private static final String PREFIX_ARM = "ARM";
private static final String EXTERNAL_WIN = ".dll";
private static final String EXTERNAL_LINUX = ".so";
private static final String EXTERNAL_MAC = ".dylib";
private static DynamicParseUtil dynamicParseUtil;
/**
* 当前读取的目录
*/
private static String currentFold;
/**
* 动态库需要写入的目录
*/
private static String EXTRACT_PATH = System.getProperty("java.io.tmpdir");
private static boolean written = false;
/**
* 设置动态库写入的路径,适用于需要自定义加载路径的用户
*
* @param path 动态库写入的文件夹,从该文件夹下加载sdk的动态库
*/
public static void setExtractPath(String path) {
EXTRACT_PATH = path;
}
/**
* 动态库路径
*/
private static String INNER_PATH;
// private static final String EXTERNAL_MAC = ".so";
private static String extractNetSDKLib(String libName) {
return extractLibrary(libName);
}
public static String getLoadLibrary(String libraryName) {
currentFold = getLibraryFold();
if (dynamicParseUtil == null) {
try {
dynamicParseUtil =
new DynamicParseUtil(
LibraryLoad.class.getClassLoader().getResourceAsStream("dynamic-lib-load.xml"));
if (!written) {
for (String libName : dynamicParseUtil.getLibsSystem(currentFold)) {
extractLibrary(libName);
}
written = true;
}
} catch (ParserConfigurationException | IOException | SAXException e) {
e.printStackTrace();
}
}
String fullName = getLibraryName(libraryName);
String path = EXTRACT_PATH;
if (!(EXTRACT_PATH.endsWith("/") || EXTRACT_PATH.endsWith("\\"))) {
path = EXTRACT_PATH + "/";
}
System.out.println("加载外部函数库: " + path + fullName);
return path + fullName;
}
/**
* 将jar包里的动态库写入到系统缓存目录,使用绝对路径加载动态库
*
* @param libName
* @return
*/
private static String extractLibrary(String libName) {
return extractLibrary("", libName);
}
/**
* 相对路径文件夹
*
* @param relativePath 相对路径
* @param libName 动态库路径
* @return
*/
private static String extractLibrary(String relativePath, String libName) {
if (libName.trim().equals("")) {
return "";
}
String libFullName = getLibraryName(libName);
String dir = getLibraryFold();
if (!(relativePath.endsWith("/") || relativePath.endsWith("\\"))) {
relativePath = relativePath + "/";
}
String fileName = relativePath + dir + "/" + libFullName;
InputStream in = LibraryLoad.class.getResourceAsStream(fileName);
BufferedInputStream reader;
FileOutputStream writer;
File extractedLibFile = null;
try {
if (in == null) {
in = new FileInputStream(fileName);
if (in == null) {
return "";
}
}
String nativeTempDir = EXTRACT_PATH;
if (!(nativeTempDir.endsWith("/") || nativeTempDir.endsWith("\\"))) {
nativeTempDir = nativeTempDir + "/";
}
extractedLibFile = new File(nativeTempDir + libFullName);
reader = new BufferedInputStream(in);
writer = new FileOutputStream(extractedLibFile);
byte[] buffer = new byte[1024];
while (true) {
int len = reader.read(buffer);
if (len == 0 || len == -1) {
break;
}
writer.write(buffer, 0, len);
}
reader.close();
writer.close();
in.close();
} catch (Exception e) {
// System.out.println(
// "dynamic file[ "
// + fileName
// + " ] not found in project.please ensure you need this library.");
}
String res = extractedLibFile != null ? extractedLibFile.getAbsolutePath() : "";
System.out.println("加载目标动态库的绝对路径为: >>>>>>> " + res);
return res;
}
/**
* 获取动态库完整名称
*
* @param libName
* @return
*/
private static String getLibraryName(String libName) {
String dir = currentFold;
String libPrefix = "";
String libExtension = EXTERNAL_WIN;
// 如果 dynamic-lib-load.xml 文件中写了扩展名,那么就不对扩展名做额外处理
if (libName.contains(".")) {
libExtension = "";
}
if (!dir.contains("win")) {
libPrefix = "lib";
if (dir.contains("linux")) {
libExtension = EXTERNAL_LINUX;
} else {
// libExtension=".dylib";
libExtension = EXTERNAL_MAC;
}
}
libName = dynamicParseUtil.compareLibName(currentFold, libName);
// 动态库以lib开头,则不添加lib前缀
// 以lib开头的库则不添加lib前缀
libName = (libName.startsWith("lib") ? "" : libPrefix) + libName + libExtension;
System.out.println("获取 dynamic-lib-load.xml 中的 动态库名称为: >>>>>>> " + libName);
return libName;
}
// 获取系统对应的动态库文件夹
private static String getLibraryFold() {
String osType;
String osName = System.getProperty("os.name");
if (osName.toLowerCase().startsWith("linux")) {
osType = ARCH_LINUX;
} else if (osName.toLowerCase().startsWith("mac")
|| osName.toLowerCase().startsWith("darwin")) {
osType = ARCH_MAC;
} else if (osName.toLowerCase().startsWith("windows")) {
osType = ARCH_WINDOWS;
} else {
osType = "";
}
String arch = System.getProperty("os.arch");
arch = arch.toLowerCase().trim();
if ("i386".equals(arch) || "i686".equals(arch) || "x86".equals(arch)) {
arch = PREFIX_32 + "";
} else if ("x86_64".equals(arch) || "amd64".equals(arch)) {
arch = PREFIX_64 + "";
} else if (arch.startsWith("arm")) {
arch = PREFIX_ARM + "";
}
System.out.println("获取系统对应平台及架构的对应匹配的动态库文件夹名称为: >>>>>>> " + osType + arch);
return osType + arch;
}
}
【dynamic-lib-load.xml】
<?xml version="1.0" encoding="UTF-8" ?>
<dynamic-lib>
<win64> <!-- 这个是平台类型与架构,需要与resources目录保持一致才能正常匹配 -->
<lib>AudioRender</lib>
<lib>HCCore</lib>
<lib>HCNetSDK</lib>
<lib>hlog</lib>
<lib>hpr</lib>
<lib>libeay32</lib>
<lib>PlayCtrl</lib>
<lib>ssleay32</lib>
<lib>SuperRender</lib>
<lib>zlib1</lib>
<!-- 带文件夹的写法 -->
<lib>HCNetSDKCom/AnalyzeData.dll</lib>
<lib>HCNetSDKCom/AudioIntercom.dll</lib>
<lib>HCNetSDKCom/AudioRender.dll</lib>
<lib>HCNetSDKCom/HCAlarm.dll</lib>
<lib>HCNetSDKCom/HCAlarm.lib</lib>
<lib>HCNetSDKCom/HCCoreDevCfg.dll</lib>
<lib>HCNetSDKCom/HCDisplay.dll</lib>
<lib>HCNetSDKCom/HCGeneralCfgMgr.dll</lib>
<lib>HCNetSDKCom/HCGeneralCfgMgr.lib</lib>
<lib>HCNetSDKCom/HCIndustry.dll</lib>
<lib>HCNetSDKCom/HCPlayBack.dll</lib>
<lib>HCNetSDKCom/HCPreview.dll</lib>
<lib>HCNetSDKCom/HCPreview.lib</lib>
<lib>HCNetSDKCom/HCVoiceTalk.dll</lib>
<lib>HCNetSDKCom/libiconv2.dll</lib>
<lib>HCNetSDKCom/OpenAL32.dll</lib>
<lib>HCNetSDKCom/StreamTransClient.dll</lib>
<lib>HCNetSDKCom/SystemTransform.dll</lib>
</win64>
<win32>
<lib>avnetsdk</lib>
<lib>dhconfigsdk</lib>
<lib>dhnetsdk</lib>
<lib>dhplay</lib>
<lib>Infra</lib>
<lib>ImageAlg</lib>
<lib>StreamConvertor</lib>
<lib>jninetsdk</lib>
</win32>
<linux64>
<lib>avnetsdk</lib>
<lib>dhnetsdk</lib>
<lib>dhconfigsdk</lib>
<lib>StreamConvertor</lib>
<lib>jninetsdk</lib>
</linux64>
<linux32>
<lib>avnetsdk</lib>
<lib>dhconfigsdk</lib>
<lib>dhnetsdk</lib>
<lib>StreamConvertor</lib>
<lib>jninetsdk</lib>
</linux32>
<mac64>
<lib>avnetsdk</lib>
<lib>dhnetsdk</lib>
<lib>dhconfigsdk</lib>
<lib>StreamConvertor</lib>
</mac64>
</dynamic-lib>
使用
public interface NetSDKLib extends Library {
NetSDKLib NETSDK_INSTANCE = Native.load(LibraryLoad.getLoadLibrary("dhnetsdk"), NetSDKLib.class);
// 动态库的 jna 代码
// ...
// ...
}
标签:libName,String,lib,HCNetSDKCom,private,JNA,static,动态链接库,加载
From: https://www.cnblogs.com/hhddd-1024/p/17097895.html