package chuankou;
|
|
import java.io.File;
|
import java.io.FileOutputStream;
|
import java.io.InputStream;
|
import java.net.URISyntaxException;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.nio.file.Paths;
|
import java.nio.file.StandardCopyOption;
|
|
/**
|
* 修复 jSerialComm 库加载问题
|
*/
|
public final class SerialPortNativeLoader {
|
private static final String LIB_PROPERTY = "com.fazecast.jSerialComm.library.path";
|
private static final String EXPECTED_DLL = "jSerialComm.dll";
|
private static volatile boolean libraryConfigured = false;
|
|
// 静态块:确保在任何 SerialPort 类加载之前运行
|
static {
|
ensureLibraryPresentEarly();
|
}
|
|
private SerialPortNativeLoader() {
|
// utility class
|
}
|
|
/**
|
* 早期初始化 - 在静态块中运行
|
*/
|
private static synchronized void ensureLibraryPresentEarly() {
|
if (libraryConfigured) {
|
return;
|
}
|
|
System.out.println("开始初始化 jSerialComm 本地库...");
|
|
// 第一步:设置系统属性,阻止自动下载
|
setCriticalSystemProperties();
|
|
// 第二步:尝试从项目资源中提取 DLL
|
try {
|
extractNativeLibraryFromResources();
|
libraryConfigured = true;
|
System.out.println("jSerialComm 本地库初始化成功");
|
} catch (Exception e) {
|
System.err.println("从资源提取 DLL 失败: " + e.getMessage());
|
// 尝试备用方案
|
try {
|
setupLibraryFromFileSystem();
|
libraryConfigured = true;
|
System.out.println("从文件系统加载 jSerialComm 成功");
|
} catch (Exception ex) {
|
System.err.println("所有加载方式都失败: " + ex.getMessage());
|
// 最后尝试:允许 jSerialComm 使用默认方式
|
allowDefaultBehavior();
|
}
|
}
|
}
|
|
/**
|
* 设置关键系统属性(在类加载前必须设置)
|
*/
|
private static void setCriticalSystemProperties() {
|
// 阻止自动下载和端口代理
|
System.setProperty("com.fazecast.jSerialComm.port.agent", "disabled");
|
System.setProperty("com.fazecast.jSerialComm.autoload", "false");
|
System.setProperty("com.fazecast.jSerialComm.autoDispose", "false");
|
|
// 禁用日志和调试
|
System.setProperty("com.fazecast.jSerialComm.debug", "false");
|
System.setProperty("com.fazecast.jSerialComm.log", "false");
|
|
System.out.println("已设置 jSerialComm 系统属性");
|
}
|
|
/**
|
* 从 JAR 资源中提取 DLL
|
*/
|
private static void extractNativeLibraryFromResources() throws Exception {
|
// 确定目标路径
|
String tempDir = System.getProperty("java.io.tmpdir");
|
Path targetDir = Paths.get(tempDir, "jSerialComm", "2.10.4");
|
|
// 如果目录不存在,创建它
|
if (!Files.exists(targetDir)) {
|
Files.createDirectories(targetDir);
|
}
|
|
Path dllPath = targetDir.resolve(EXPECTED_DLL);
|
|
// 检查 DLL 是否已存在且可用
|
if (Files.exists(dllPath)) {
|
System.out.println("DLL 已存在于: " + dllPath);
|
// 设置库路径
|
System.setProperty(LIB_PROPERTY, targetDir.toString());
|
return;
|
}
|
|
// 从类路径资源加载 DLL
|
String resourcePath = "/native/windows/x86_64/" + EXPECTED_DLL;
|
InputStream dllStream = SerialPortNativeLoader.class.getResourceAsStream(resourcePath);
|
|
if (dllStream == null) {
|
// 尝试其他可能的路径
|
resourcePath = "/lib/native/windows/x86_64/" + EXPECTED_DLL;
|
dllStream = SerialPortNativeLoader.class.getResourceAsStream(resourcePath);
|
}
|
|
if (dllStream == null) {
|
// 尝试从文件系统加载
|
resourcePath = "lib/native/windows/x86_64/" + EXPECTED_DLL;
|
File file = new File(resourcePath);
|
if (file.exists()) {
|
dllStream = Files.newInputStream(file.toPath());
|
}
|
}
|
|
if (dllStream == null) {
|
throw new RuntimeException("无法在资源中找到 " + EXPECTED_DLL);
|
}
|
|
// 复制 DLL 到临时目录
|
try (InputStream is = dllStream;
|
FileOutputStream fos = new FileOutputStream(dllPath.toFile())) {
|
|
byte[] buffer = new byte[8192];
|
int bytesRead;
|
while ((bytesRead = is.read(buffer)) != -1) {
|
fos.write(buffer, 0, bytesRead);
|
}
|
}
|
|
System.out.println("DLL 已提取到: " + dllPath);
|
|
// 设置库路径
|
System.setProperty(LIB_PROPERTY, targetDir.toString());
|
System.setProperty("java.library.path",
|
System.getProperty("java.library.path") + File.pathSeparator + targetDir.toString());
|
}
|
|
/**
|
* 从文件系统设置库
|
*/
|
private static void setupLibraryFromFileSystem() throws Exception {
|
// 检查多个可能的路径
|
String[] possiblePaths = {
|
"lib/native/windows/x86_64/" + EXPECTED_DLL,
|
"./lib/native/windows/x86_64/" + EXPECTED_DLL,
|
System.getProperty("user.dir") + "/lib/native/windows/x86_64/" + EXPECTED_DLL,
|
"../lib/native/windows/x86_64/" + EXPECTED_DLL
|
};
|
|
for (String path : possiblePaths) {
|
File dllFile = new File(path);
|
if (dllFile.exists()) {
|
System.out.println("找到 DLL: " + dllFile.getAbsolutePath());
|
// 使用 DLL 所在目录
|
File parentDir = dllFile.getParentFile();
|
System.setProperty(LIB_PROPERTY, parentDir.getAbsolutePath());
|
System.setProperty("java.library.path",
|
System.getProperty("java.library.path") + File.pathSeparator + parentDir.getAbsolutePath());
|
return;
|
}
|
}
|
|
throw new RuntimeException("在文件系统中找不到 " + EXPECTED_DLL);
|
}
|
|
/**
|
* 允许默认行为(最后的手段)
|
*/
|
private static void allowDefaultBehavior() {
|
System.err.println("警告:使用 jSerialComm 的默认加载行为");
|
// 清空阻止属性,让 jSerialComm 自己处理
|
System.clearProperty("com.fazecast.jSerialComm.autoload");
|
System.clearProperty("com.fazecast.jSerialComm.port.agent");
|
}
|
|
/**
|
* 公共方法 - 供其他代码调用
|
*/
|
public static synchronized void ensureLibraryPresent() {
|
// 静态块已经执行,这里只是确保
|
if (!libraryConfigured) {
|
ensureLibraryPresentEarly();
|
}
|
}
|
}
|