我们在使用第三方动态库 时长出现动态库无法读取jar包内的动态库文件,以下代码希望对大家有帮助
<?xml version="1.0" encoding="UTF-8" ?>
<dynamic-lib>
<win64>
<lib>avnetsdk</lib>
<lib>dhconfigsdk</lib>
<lib>dhnetsdk</lib>
<lib>dhplay</lib>
<lib>ImageAlg</lib>
<lib>Infra</lib>
<lib>IvsDrawer</lib>
<lib>StreamConvertor</lib>
<lib>jninetsdk</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>
@Slf4j
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;
}
public static String getExtractPath() {
return EXTRACT_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 (Exception e) {
e.printStackTrace();
}
}
String fullName = getLibraryName(libraryName);
String path = EXTRACT_PATH;
if (!(EXTRACT_PATH.endsWith("/") || EXTRACT_PATH.endsWith("\\"))) {
path = EXTRACT_PATH + "/";
}
log.info("load library: " + 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 + "libs/" + 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) {
log.error("dynamic file[ "
+ fileName
+ " ] not found in project.please ensure you need this library.");
}
return extractedLibFile != null ? extractedLibFile.getAbsolutePath() : "";
}
/**
* 获取动态库完整名称
*
* @param libName
* @return
*/
private static String getLibraryName(String libName) {
String dir = currentFold;
String libPrefix = "";
String libExtension = EXTERNAL_WIN;
if (!dir.contains("win")) {
libPrefix = "lib";
if (dir.contains("linux")) {
libExtension = EXTERNAL_LINUX;
log.info("当前为LINUX环境");
} else {
// libExtension=".dylib";
libExtension = EXTERNAL_MAC;
log.info("当前为MAC环境");
}
}
log.info("当前为win环境");
libName = dynamicParseUtil.compareLibName(currentFold, libName);
// 动态库以lib开头,则不添加lib前缀
// 以lib开头的库则不添加lib前缀
return (libName.startsWith("lib") ? "" : libPrefix) + libName + libExtension;
}
// 获取系统对应的动态库文件夹
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 + "";
}
return osType + arch;
}
}
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.toLowerCase().contains("win")) {
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 (Exception e) {
e.printStackTrace();
}
}
public DynamicParseUtil(InputStream inputSteam)
throws ParserConfigurationException, IOException, SAXException {
this();
saxParser.parse(inputSteam, handler);
}
/**
* xml解析handler
*/
private class DynamicLibParseHandler extends DefaultHandler {
private HashMap<String, List<String>> dynamics = new HashMap<String, List<String>>();
private 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<String>();
}
}
}
@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);
}
}
}
}
public interface NetSDKLib extends Library {
NetSDKLib NETSDK_INSTANCE = Native.load(LibraryLoad.getLoadLibrary("dhnetsdk"), NetSDKLib.class);
}