运行 JAR(Fxyz3d 库)时出现 FileSystemNotFoundException
Posted
技术标签:
【中文标题】运行 JAR(Fxyz3d 库)时出现 FileSystemNotFoundException【英文标题】:FileSystemNotFoundException while running JAR (Fxyz3d library) 【发布时间】:2020-10-18 00:25:32 【问题描述】:我构建了一个相当大的 JavaFX 应用程序(JAR 大约 128 MB),通过 IntelliJ 运行没有问题。但是当我从终端运行它时,我的 3D 模型加载器(Fxyz3d 库)会启动此异常。
Exception in thread "JavaFX Application Thread" java.nio.file.FileSystemNotFoundException
at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:172)
at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:158)
at java.base/java.nio.file.Path.of(Path.java:208)
at java.base/java.nio.file.Paths.get(Paths.java:98)
at org.fxyz3d.importers.obj.ObjImporter.read(ObjImporter.java:115)
at org.fxyz3d.importers.obj.ObjImporter.loadAsPoly(ObjImporter.java:102)
at org.fxyz3d.importers.Importer3D.loadIncludingAnimation(Importer3D.java:160)
at org.fxyz3d.importers.Importer3D.loadAsPoly(Importer3D.java:80)
at it.polimi.ingsw.PSP50.View.GUI.GuiView.lambda$startingGame$1(GuiView.java:201)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
这仅适用于 Fxyz3d 库中的 3D 对象加载器,而不适用于我的其他普通 FXML 加载器。我使用相同的方式从我的 src/main/resources 文件夹中获取文件,即 getClass().getResource。 那么这真的是路径问题吗?还是图书馆的问题? 相反,在 IntelliJ 中完全没有问题,一切正常。 这是代码中不起作用的部分:
Model3D boardModel = Importer3D.loadAsPoly(getClass().getResource("/boardcliff2.obj"));
如果有人以前遇到过这样的事情并且知道发生了什么,我们将非常感激帮助
【问题讨论】:
根据您在问题中发布的堆栈跟踪,org.fxyz3d.importers.obj.ObjImporter
类中的方法read()
调用java.nio.file.Paths
类的方法get()
,最终导致抛出异常。当您调用方法Paths.get()
时,您提供了哪些参数? (参考文件ObjImporter.java
中的第115行)
有一些refactoring 和BufferedReader
被替换为Files.lines
以读取模型文件。 FXyz 示例查看器适用于使用 gradle 和 JavaFX 插件的ImportObj sample,但我在使用jlink
时遇到了类似的错误,所以是的,目前最好的方法是提交问题。
作为一种解决方法,您可以添加一些代码来将 obj/mtl 文件提取到 tmp 位置,然后使用带有file://
协议的 url。
@José 请注意,您在使用链接运行时映像时看到的问题(我假设)应该在 Java 13+ 中no longer occur。但是,当资源嵌入到 JAR 文件中时,仍然会发生 OP 遇到的错误。
感谢@Slaw,确实它已为 jlink 修复。我提交了错误:github.com/FXyz/FXyz/issues/108.
【参考方案1】:
José Pereda 为此开设了an issue,此后一直是been fixed。截至目前(2020 年 8 月 14 日),FXyz 的最新版本为 0.5.2,其中不包含此问题的修复程序。您可以继续使用此答案中显示的解决方法,从最近的提交中自己构建库,或等待库的下一个版本。
这似乎是实施的问题。它尝试将URL
转换为Path
,但必要的FileSystem
不存在1。最好的解决方法可能是将资源提取到临时文件中,然后从所述文件中导入对象。这样,URL 将具有file:
协议,并且可以转换为Path
(默认的FileSystem
始终存在)。以下是如何提取资源的示例:
// Note: 'Path' is 'java.nio.file.Path', not 'javafx.scene.shape.Path'
public static Path copyToTempFile(URL url, String suffix) throws IOException
// 'suffix' will default to ".tmp" if null
Path tempFile = Files.createTempFile(null, suffix);
try (InputStream in = url.openStream();
OutputStream out = Files.newOutputStream(tempFile))
in.transferTo(out); // 'transferTo' method added in Java 9
return tempFile;
然后您可以使用生成的Path
来导入 3D 对象:
Path tempFile = copyToTempFile(getClass().getResource("/boardcliff2.obj"), ".obj");
Model3D boardModel = Importer3D.loadAsPoly(tempFile.toUri().toURL());
如果需要,您可以在完成后删除临时文件。
1.当嵌入到 JAR 文件中时,资源的 URL 具有 jar:
协议。这意味着来自ZIP FileSystemProvider 的FileSystem
,打开到特定的ZIP/JAR 文件,必须存在才能转换为Path
。如果实现只是使用URL#openStream()
,则不会发生此问题,它通过不同的机制访问 JAR 条目。
【讨论】:
【参考方案2】:除了 Slaw 的解决方案之外,我的一位同事找到了另一种解决方案:将这些代码行添加到 ObjImporter 类(Fxyz3d 库)中的函数 loadAsPoly 可以解决每次导入的问题。
public class ObjImporter implements Importer
...
@Override
public Model3D loadAsPoly(URL url) throws IOException
// Additional lines
if(url.getProtocol().equals("jar"))
try
Map<String, String> env = new HashMap<>();
env.put("create", "true");
FileSystem zipfs = FileSystems.newFileSystem(url.toURI(), env);
catch(FileSystemAlreadyExistsException ignored)
catch (IOException | URISyntaxException e)
e.printStackTrace();
// End of the addition
return read(url, true);
...
我用我的 Jar 对其进行了测试,它也能正常工作(当然,在我的项目中,我将 Fxyz 库中的必要类导入到我的 Utils 包中)。
【讨论】:
请注意,与其将文件从 FXyz3D 复制到您的项目中,不如创建一个执行上述操作然后调用Importer3D.loadAsPoly
的实用程序方法可能更容易。以上是关于运行 JAR(Fxyz3d 库)时出现 FileSystemNotFoundException的主要内容,如果未能解决你的问题,请参考以下文章
作为 jar 运行时出现 FileNotFoundException
在 android 2.3 上使用 jcifs 库时出现 NoClassDefFound 异常
运行使用 SBT 和 ProGuard 构建的独立 jar 时出现 AbstractMethodError