无法在可执行 jar 中运行的 java 项目中找到文件

Posted

技术标签:

【中文标题】无法在可执行 jar 中运行的 java 项目中找到文件【英文标题】:Unable to locate a file in java project running in a executable jar 【发布时间】:2018-02-15 09:59:52 【问题描述】:

class.getResource(FILE_NAME)class.getClass().getClassLoader().getResource(FILE_NAME) 在我的 Eclipse 中完美运行,但是当在 Windows 机器中作为可执行 jar 运行时,相同的代码无法找到 jar 文件中的文件。

我已经浏览了所有可用于此问题的相关链接(嗯,不是完全相同的问题,但 90% 是同步的),要求解决方案,但没有任何回复来自这些帖子,所以我将我的问题发布为一个单独的问题,希望对此有所帮助。

我总共解决了 4 个案例,但到目前为止没有一个有效,我现在没有想法了。

class.getClass().getClassLoader().getResource("/resources/readme.txt");
class.getResource("/resources/readme.txt");
class.getClass().getClassLoader().getResource("resources/readme.txt");
class.getResource("resources/readme.txt");

上述4个案例中,只有2个案例在eclipse中运行成功,如下所述。

class.getResource("/resources/readme.txt");
class.getClass().getClassLoader().getResource("resources/readme.txt");

其他 2 种情况只是在线程“main”java.lang.NullPointerException 中向我抛出异常

来到可执行 jar,所有 4 个案例都向我抛出了 Exception in thread "main" java.lang.NullPointerException

所以我创建了一个名为 resources 的文件夹,我的 jar 位于该文件夹中,并将我的文件放在该文件夹中并运行 jar。现在 jar 正在运行,没有任何问题引用我创建的 resources 文件夹中的文件。所以无论我在哪里运行这个 jar(windows、linux 等),我都需要创建一个 resources 文件夹并将我的文件放在该文件夹下。现在的问题是,是否可以让我的 jar 引用 jar 本身内部的 resources 文件夹?

非常感谢您对此的任何帮助!

【问题讨论】:

究竟是什么引发了 NullPointerException?它不能是 Class.getResource() 方法——只有在你传递一个空参数时才会抛出异常,而你没有这样做。所以它一定是你自己的代码里面的东西。 Class.getResource() 方法是否返回 null 而您不检查它是否为 null? getResource()找不到文件时,一般会抛出NullPointerException 不,它不会抛出 NullPointerException 除非你传递一个空参数。如果它找不到资源,它将返回 null。正如文档中所说:docs.oracle.com/javase/9/docs/api/java/lang/… 我的错,我对 null 和 NullPointerException 感到困惑。是的,当它无法找到文件时它返回 null 并且在 null 之上我正在尝试进一步的操作,这会抛出 NullPointerException。 如果您在 zip 查看器(例如 7-zip、winzip、winrar 等)中查看可执行 jar 文件或者您输入命令 jar -tf yourfile.jar,您能看到您的 readme.txt 文件吗? 【参考方案1】:

要获取您的 txt 文件:

File yourFileIsHere = new File("resources/readme.txt");

您的文件放在哪里?

在你的 jar 的同一位置,例如:

myapp/yourjar.jar

myapp/resources/readme.txt

如果您想读取“src”文件夹中的文件:

InputStream yourInputStream = new YourClass().getClass().getClassLoader().getResourceAsStream("readme.txt");

【讨论】:

resources 文件夹在 src 文件夹下 当我将我的项目导出为 jar 时,它将是 myapp.jar,我的文件将在 jar 中 InputStream yourInputStream = new YourClass().getClass().getClassLoader().getResourceAsStream("readme.txt"); 仅在文件 readme.txt 直接位于 src 文件夹内时才有效。但我的readme.txt 在 src\resources 文件夹下 当然,有很多方法可以做到这一点,让我们一个简单的方法,没有任何库: byte[] bytes = new byte[yourInputStream.available()];你的InputStream.read(字节);你的InputStream.close(); //关闭输入流,已读取字节。 FileOutputStream fos = new FileOutputStream(new File("your_path_file")); fos.write(字节); fos.close(); //关闭文件输出流。 等一下,你想写入到readme.txt吗?你不能。一旦文件在 jar 中,它就是只读的。【参考方案2】:

如果您使用的是 Spring:

org.springframework.util.ResourceUtils.getFile("classpath:readme.txt")

否则:

import com.google.common.io.Resources

byte[] byteSource = Resources.asByteSource(Resources.getResource("readme.txt")).read()

【讨论】:

不使用 Spring,因此将尝试您提到的“否则”选项。您能帮我了解如何将对象byteSource 传递给“FileOutputStream”类吗?【参考方案3】:

方法class.getClass().getClassLoader().getResource() 可能需要3 个前缀:url:classpath:file:,每个前缀都说明了您的搜索基础。如果要在 jar 中搜索,请使用 classpath: 前缀。这告诉你的类加载器在你的类路径中搜索任何地方。这里有一个example如何使用Spring工具来处理它。还请查看 Spring 中的 ResourceLoader 类

【讨论】:

如何使用classpath: 前缀?对不起,我这里没有使用Spring,这只是我正在使用的一个java项目。 我相信类加载器也接受这些前缀。至于如何使用前缀 - 而不是 class.getClass().getClassLoader().getResource("/resources/readme.txt");使用 class.getClass().getClassLoader().getResource("classpath:resources/readme.txt"); Exception in thread "main" java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58) Caused by: java.lang.IllegalArgumentException: name 尝试删除前导斜杠:class.getClass().getClassLoader().getResource("resources/readme.txt"); 我根本没有使用任何前导斜杠

以上是关于无法在可执行 jar 中运行的 java 项目中找到文件的主要内容,如果未能解决你的问题,请参考以下文章

Struts2无法在可执行的战争中初始化Dispatcher - 嵌入式Tomcat

无法在可部署的 .jar 中加载主类

Java:如何在可运行的 Jar 文件中打包和访问资源?

maven - 在打包的 jar 中找不到引用的库 [重复]

Maven 和 Eclipse:在 Maven 库项目中加载默认属性并在可运行的 Jar 中使用它

在可执行的 .jar 文件中包含 excel