无法在可执行 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
maven - 在打包的 jar 中找不到引用的库 [重复]