为什么我的Jar不运行,除非我提取文件? [英] Why my Jar doesn't run unless I extract files?
问题描述
每当我运行导出的 .jar
文件,其中包含一个图像为其图标的 JFrame
该文件不运行,除非我提取文件。在编译器中它正在运行。我不想制作一个将资源包和jar文件保存在目录中的启动器。
为什么我的Jar不运行,除非我提取文件?
这似乎是使用的行为文件
到您的资源。例如
文件文件=新文件(resources / image.png);
图像= ImagIO.read(file);
您的项目结构(注意资源
实际上应该在 src
中,以便它自动构建到jar中 - 除非你配置不同,但是为了这个说法,让我们说你在 c code code code code code code code $ > C:\
项目
resources\image.png
检查:
-
从IDE运行 - WORKS!为什么?使用
文件
查找文件系统上的文件。使用相对路径,搜索将从工作目录开始,在IDE的情况下,通常是项目根目录。所以resources / image.png
是一个有效的路径,相对于ProjectRoot
-
构建jar,说它最终在项目中的
dist
目录中。这是它的样子ProjectRoot
dist
ProjectRoot.jar
现在为了这个参数(实际上是正确的方式),让我们尝试打印出来的程序中的资源的URL ,所以当你运行jar时,它打印出文件的URL
URL url = Test.class.getResource /resources/image.png);
System.out.println(url.toString());
当我们运行jar
C:\ProjectRoot\dist> java -jar ProjectRoot.jar
我们将看到打印输出C:\ProjectRoot\dist\ProjectRoot.jar!\resources\image.png
。您可以看到即使当前工作目录是jar的位置,路径不再匹配,添加的jarProjectRoot.jar!
位置。 -
那么为什么在我们提取它的时候它会工作。那么当你提取它,那么路径是正确的
C:\ProjectRoot
dist
资源/image.png //从提取的jar
ProjectRoot.jar
当您从
C:\ProjectRoot\dist>
,资源
dir是应该在哪里。
足够解释。
因此,当您想要阅读嵌入式资源时,应从Andrew Thompson所提供的URL中读取。这个url应该是相对于调用它的类,或类加载器。以下是几种不同的方法:
-
如图所示
URL url = getClass()。getResource(/ resources / image.png);
注意
/
。这将使我们进入类路径的根,其中资源
目录将在。可以将URL
传递给许多构造函数,如ImageIcon(URL)
或`ImageI.read(URL) -
您可以使用
InputStream is = getClass()。的getResourceAsStream( /资源/ image.png);
哪些将使用一个URL。您可以使用
InputStream
与许多构造函数。 -
还有一些方法可以使用类加载器,将从根开始,因此您不需要
/
URL url = getClass()。getClassLoader()。getResource(resources / image.png);
所以有几种方法可以去关于它。但是一般来说,使用嵌入式资源时,用硬编码的字符串路径读取 File
并不是个好主意。可以动态获取路径,以便您可以使用文件
,但是您仍然需要使用上述技术之一,除非您真的需要一个文件
将无意义,您可以使用 InputStream
或 URL
简短描述
工作
ProjectRoot
src\resources\image.png
URL url = 。的getClass()的getResource( /资源/ image.png);
Image image = ImageIO.read(url);
Every time I run the exported .jar
file, that contains a JFrame
with an image as its icon, the file doesn't run, unless I extract the file. In the compiler it is running. I dont want to make a launcher that saves both, the resources package and the jar file, in a directory.
"Why my Jar doesn't run unless I extract files?"
This seems to be the behavior of using File
to your resources. Take for example
File file = new File("resources/image.png");
Image image = ImagIO.read(file);
And you project structure (Note the resources
should actually be in the src
, so that it builds into the jar automatically - unless you configure it differently. But for the sake of this argument, let's say you do confgigure it where resources
is built to the jar)
C:\
Project
resources\image.png
Some examination:
Run from IDE - WORKS! Why? Using
File
looks for files on the file system. Using a relative path, the search will begin from the "working directory", which in the case of the IDE in generally the project root. So"resources/image.png"
is a valid path, relative toProjectRoot
Build jar, say it ends up in a
dist
dir in the project. This is what it looks likeProjectRoot dist ProjectRoot.jar
Now for the sake of this argument (and is actually the correct way), let's try and print the URL of the resource in out program, so that when you run the jar, it prints out the URL of the file
URL url = Test.class.getResource("/resources/image.png"); System.out.println(url.toString());
When we run the jar
C:\ProjectRoot\dist> java -jar ProjectRoot.jar
We will see the print outC:\ProjectRoot\dist\ProjectRoot.jar!\resources\image.png
. You can obviously see even though the current working directory is the location of the jar, the paths no longer match, with the added jarProjectRoot.jar!
location.So why does it work when we extract it. Well when you extract it, then the path is correct
C:\ProjectRoot dist resources/image.png // from extracted jar ProjectRoot.jar
When you run from the
C:\ProjectRoot\dist >
, theresource
dir is where is should be.
Ok enough with the explanation.
For this reason, when you want to read embedded resources, they should be read from an URL as Andrew Thompson mentioned. This url should be relative to the class calling it, or the class loader. Here are a couple different ways:
As shown already
URL url = getClass().getResource("/resources/image.png");
Notice the
/
. This will bring us to the root of the classpath, where theresources
dir will be.URL
can be passed to many constructors, likeImageIcon(URL)
or `ImageI.read(URL)You can use:
InputStream is = getClass().getResourceAsStream("/resources/image.png");
Which will use an URL under the hood. You can use
InputStream
with many constructors also.There's also ways to use the class loader, which will start at the root, so you don't need the
/
URL url = getClass().getClassLoader().getResource("resources/image.png");
So there are a few ways you can go about it. But in general, reading File
with hard coded string paths is never a good idea, when using embedded resources. It's possible to obtain the path dynamically so you can use File
, but you will still need to use one of the aforementioned techniques, which unless you really need a File
would be pointless, as you can do what you need with the InputStream
or URL
To make a long story short
This would work
ProjectRoot
src\resources\image.png
URL url = getClass().getResource("/resources/image.png");
Image image = ImageIO.read(url);
这篇关于为什么我的Jar不运行,除非我提取文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!