如何告诉Java JAR文件中正确的文件路径?

时间:2019-05-30 23:36:40

标签: java javafx java-11 openjfx

我已将所有JavaFX代码放入可执行的JAR文件中。一切都在里面。

当我使用Eclipse IDE进行编译时,它可以工作,但是当我尝试执行JAR文件时,出现错误。

Caused by: javafx.fxml.LoadException: 
file:/home/asus/program/JUSBPlotter/JUSBPlotter-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/se/danielmartensson/fxml/front.fxml

当我有此Java代码

 Parent root = FXMLLoader.load(getClass().getResource("/se/danielmartensson/fxml/front.fxml"));

FXML文件没有问题。

fx:controller="se.danielmartensson.controller.Front"

当我尝试在JavaFX中显示图片时,也会出错。

Caused by: java.io.FileNotFoundException: file:/home/asus/program/JUSBPlotter/JUSBPlotter-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/se/danielmartensson/pictures/computer.png (No such file or directory)

当我有以下Java代码时:

FileInputStream picture1 = new FileInputStream(getClass().getResource("/se/danielmartensson/pictures/computer.png").getFile());

问题: 如何告诉Java JAR文件中正确的文件路径?

1 个答案:

答案 0 :(得分:2)

要记住的一件事是,资源与文件不是同一件事,尽管它们看起来非常相似,尤其是在打包应用程序之前。打包应用程序后,这些资源文件将成为JAR文件中的条目,尽管可以将它们视为文件,但无法以与文件相同的方式进行访问。尤其是java.io.File API无法理解如何读取这些条目。但是,您可以通过Class#getResource(String)返回的URLClass#getResourceAsStream(String)返回的InputStream访问这些条目。请注意,后者基本上只是找到URL,如果存在,则调用URL#openStream()。您可以使用URL访问JAR条目(即资源)的原因是由于JarURLConnection和相关类;我不会详细介绍Java如何处理URL,因为这超出了此答案的范围。

现在,由于您尝试在JavaFX中显示图像,因此我假设您正在使用Image类。基本上可以通过三种方式告诉Image图片资源在哪里。

  1. 在参数URL没有方案的地方使用Image#<init>(String)。在这种情况下,类会将URL视为相对于类路径根目录的路径,并尝试相应地访问图像。基本上,该参数与您为Class#getResource(String)提供的参数相同,只是路径必须是绝对的(即,不是相对于任何类的)。 Image类对此行为进行了记录:

      

    URL支持的所有URL都可以传递给构造函数。如果传递的字符串不是有效的URL,而是一个路径,则在这种情况下,将在类路径上搜索Image。

    注意:如果您使用的是模块,则使用此选项时resource encapsulation会起作用。参见GitHub Issue #441

  2. 使用与上述相同的构造函数,但传递有效的URL(即,它具有方案)。使用资源时,您可以简单地使用URL#toExternalForm()URL返回的Class#getResource(Sring)转换为String

    Image image = new Image(getClass().getResource(...).toExternalForm());
    

    注意:您也可以使用URL#toString()返回相同的值。

  3. 使用Image#<init>(InputStream)。在这里您可以使用Class#getResourceAsStream(String)。完成操作后,别忘了关闭InputStream

    try (InputStream is = getClass().getResourceAsStream(...)) {
        Image image = new Image(is);
    }
    

所有这些都假定在构建资源时,这些资源已正确打包在JAR文件中。如果不是这种情况,请首先遵循JoséPereda在问题评论中提供的建议。


请注意,可以使用java.util.zip.* API,java.util.jar.* API或Java NIO的ZipFileSystemProvider访问ZIP / JAR文件的条目。所有这些选项,尤其是最后一个选项,都使您可以访问与实际文件类似的ZIP / JAR文件条目,因为它们是专门为这样做而设计的。但是,在应用程序中使用资源时,应坚持使用Class#getResource(String)和相关方法。