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(); } } }