简体   繁体   English

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

[英]How to tell Java the correct file path in a JAR-file?

I have put all my JavaFX code into a executable JAR-file. 我已将所有JavaFX代码放入可执行的JAR文件中。 Everything is inside there. 一切都在里面。

When I compile it with Eclipse IDE, it works, but when I try to execute the JAR-file, I get an error. 当我使用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

When I have this Java code 当我有这个Java代码时

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

There is nothing wrong with the FXML file. FXML文件没有任何问题。

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

Also I get errors when I try to display a picture in JavaFX. 当我尝试在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)

When I have this Java code: 当我有此Java代码时:

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

Question: How can I tell Java the correct file path in JAR-file? 问题:如何告诉Java JAR文件中正确的文件路径?

One thing to remember is that resources are not the same thing as files, despite the fact they appear quite similar—especially before packaging an application. 要记住的一件事是,资源与文件不是一样的东西,尽管它们看起来非常相似,尤其是在打包应用程序之前。 Once you package an application those resource files become entries in a JAR file which, while they can be thought of as files, cannot be accessed in the same way as files. 打包应用程序后,这些资源文件将成为JAR文件中的条目,尽管可以将它们视为文件,但无法以与文件相同的方式进行访问。 In particular, the java.io.File API does not understand how to read those entries. 特别是, java.io.File API无法理解如何读取这些条目。 You can, however, access these entries through the URL returned by Class#getResource(String) or the InputStream returned by Class#getResourceAsStream(String) . 你可以,但是,通过访问这些条目URL由归国Class#getResource(String)InputStream由归国Class#getResourceAsStream(String) Note the latter basically just finds the URL and, if it exists, calls URL#openStream() . 请注意,后者基本上只是找到URL ,如果存在,则调用URL#openStream() The reason you can access JAR entries (ie resources) with the URL is due to the JarURLConnection and related classes; 您可以使用URL访问JAR条目(即资源)的原因是由于JarURLConnection和相关的类; I won't go into detail about how URLs are handled by Java as that's out of scope for this answer. 我不会详细介绍Java如何处理URL,因为这超出了此答案的范围。

Now, since you're trying to display an image in JavaFX I assume you're using the Image class. 现在,由于您试图在JavaFX中显示图像,因此我假设您正在使用Image类。 There are basically three ways you can tell an Image where the image resource is. 基本上可以通过三种方法告诉Image图像资源在哪里。

  1. Use Image#<init>(String) where the argument URL has no scheme. 使用Image#<init>(String) ,其中参数URL没有方案。 In this case the class will treat the URL as a path relative to the root of the classpath and try to access the image accordingly. 在这种情况下,类会将URL视为相对于类路径根目录的路径,并尝试相应地访问图像。 Basically, the argument is the same argument you'd give to Class#getResource(String) , except that the path must be absolute (ie not relative to any class). 基本上,该参数与您给Class#getResource(String)相同的参数,只是路径必须是绝对的(即,相对于任何类都不是相对的)。 This behavior is documented by the Image class: 此行为由Image类记录:

    All URLs supported by URL can be passed to the constructor. URL支持的所有URL都可以传递给构造函数。 If the passed string is not a valid URL, but a path instead, the Image is searched on the classpath in that case. 如果传递的字符串不是有效的URL,而是有效的路径,则在这种情况下,将在类路径中搜索Image。

    Note: If you're using modules then resource encapsulation comes into play when using this option. 注意:如果您正在使用模块,则使用此选项时, 资源封装将发挥作用。 See GitHub Issue #441 . 参见GitHub Issue#441

  2. Use the same constructor as used above but pass a valid URL (ie it has a scheme). 使用与上面使用的相同的构造函数,但传递一个有效的URL(即,它具有一个方案)。 When using a resource, you can simply convert the URL returned by Class#getResource(Sring) into a String using URL#toExternalForm() . 使用资源时,您只需使用URL#toExternalForm()Class#getResource(Sring)返回的URL转换为String URL#toExternalForm()

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

    Note: You can also use URL#toString() which returns the same value. 注意:您也可以使用URL#toString()返回相同的值。

  3. Use Image#<init>(InputStream) . 使用Image#<init>(InputStream) Here you can use Class#getResourceAsStream(String) . 在这里,您可以使用Class#getResourceAsStream(String) Don't forget to close the InputStream when done with it. 不要忘记关闭InputStream时,用它做。

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

All this assumes that the resources have been properly packaged in your JAR file when you built it. 所有这些都假定在构建资源时,这些资源已正确包装在JAR文件中。 If that's not the case, follow the advice given by José Pereda in the question comments first. 如果不是这种情况,请首先按照JoséPereda在问题评论中提供的建议进行操作。


Note that one can access the entries of a ZIP/JAR file using the java.util.zip.* API, the java.util.jar.* API, or the Java NIO's ZipFileSystemProvider . 请注意,可以使用java.util.zip.* API, java.util.jar.* API或Java NIO的ZipFileSystemProvider访问ZIP / JAR文件的ZipFileSystemProvider Each of these, especially the last option, allow you to access the entries of a ZIP/JAR file similar to actual files because they're designed specifically to do so. 所有这些选项,尤其是最后一个选项,都使您可以访问与实际文件类似的ZIP / JAR文件条目,因为它们是专门为这样做而设计的。 However, when using resources in an application you should stick with Class#getResource(String) and related methods. 但是,在应用程序中使用资源时,应坚持使用Class#getResource(String)和相关方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM