JDK19 Swing程序Jar包访问共享目录报错,IDEA运行正常求助
我用JDK 19开发了一款带Swing GUI的桌面应用,功能是解析文件元数据,将文件从指定文件夹移动至共享驱动器(会检查所需目录是否存在,不存在则创建并复制文件)。在IDEA中运行时一切正常,但打包为可执行Jar后,设置相同参数运行却出现如下错误:
Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: java.nio.file.FileSystemException: V:\!РОЛИКИ\Москва Хорошо\Test\2023\14.01: Unable to determine if root directory exists at gui.GUITest$1.actionPerformed(GUITest.java:52) at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1972) at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2313) at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405) at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262) at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279) at java.desktop/java.awt.Component.processMouseEvent(Component.java:6620) at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3398) at java.desktop/java.awt.Component.processEvent(Component.java:6385) at java.desktop/java.awt.Container.processEvent(Container.java:2266) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4995) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4827) at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4948) at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4575) at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4516) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4827) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714) at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) Caused by: java.nio.file.FileSystemException: V:\!РОЛИКИ\Москва Хорошо\Test\2023\14.01: Unable to determine if root directory exists at java.base/java.nio.file.Files.createDirectories(Files.java:782) at core.Autosort.moveVideoToServer(Autosort.java:66) at core.Autosort.VLCjAutosort(Autosort.java:53) at core.Autosort.sortFiles(Autosort.java:31) at gui.GUITest$1.actionPerformed(GUITest.java:48)
我不清楚问题出在哪里,如何让可执行Jar实现和IDEA中相同的运行效果?我搜索到原因可能和Windows SMB有关,但为何在IDEA中运行正常?
核心原因
IDEA运行与Jar运行的关键差异在于权限上下文和网络驱动器访问逻辑:
- IDEA直接在当前用户会话下启动JVM,完全继承用户的网络驱动器映射权限,能正常识别V盘这类SMB映射盘符。
- 可执行Jar若通过双击启动,部分系统中Jar关联的JVM进程不会加载用户的网络驱动器映射;或者JVM在Jar模式下对SMB路径的解析存在差异,无法识别映射盘符对应的共享目录。
具体解决步骤
改用UNC路径替代映射盘符
放弃使用V:\!РОЛИКИ\Москва Хорошо\Test\2023\14.01这类映射盘符路径,直接使用SMB共享的UNC路径,例如\\服务器主机名\共享文件夹名\!РОЛИКИ\Москва Хорошо\Test\2023\14.01。这种方式绕开本地盘符映射限制,让JVM直接通过网络协议访问共享目录。以用户权限启动Jar
不要双击Jar文件运行,而是打开CMD命令提示符,切换到Jar所在目录,执行命令:java -jar 你的应用文件名.jar若需要双击启动,可创建一个批处理文件(.bat),内容为上述命令,双击批处理文件即可继承当前用户的完整权限。
优化文件操作的异常处理
在调用Files.createDirectories()前,手动检查父目录存在性,并捕获更具体的IO异常,便于定位问题。示例代码:Path targetDir = Paths.get("\\server\\share\\your\\target\\path"); try { // 先检查并创建父目录 Path parentDir = targetDir.getParent(); if (parentDir != null && !Files.exists(parentDir)) { Files.createDirectories(parentDir); } Files.createDirectories(targetDir); } catch (IOException e) { System.err.println("创建目录失败: " + targetDir); System.err.println("错误详情: " + e.getMessage()); e.printStackTrace(); }验证JDK版本一致性
确保打包Jar时使用的JDK版本与IDEA中运行的JDK 19完全一致,避免版本差异导致的SMB访问逻辑不同。
内容的提问来源于stack exchange,提问作者danilasar

