从jar里面获取资源文件
Getting resource file from inside jar
当应用程序打包到 jar 中时,我需要从应用程序的根目录中获取资源。我的项目是这样的:
ProjectRoot
resource.txt //want to access from here
src
main
java
package1
package2
package3
Main.java
target
app.jar
classes
resource.txt //works when here
package1
package2
package3
Main.class
我使用这个代码:
Path path = Paths.get("resource.txt");
当 运行 打包成 jar 之前,它发现文件很好(在 ProjectRoot 中)。 运行ning jar 时找不到,将此路径转换为target/resource.txt
.
此代码:
BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
"resource.txt")));
当运行打包前找target/classes
里面的资源。打包后它声称从 .../target/app.jar!/resource.txt
.
获取资源
此代码:
BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
"/resource.txt")));
我不明白在哪里寻找资源,但它似乎不是ProjectRoot
。
我想要做的就是将资源放在 ProjectRoot
中,并能够从两个外部 jar 访问它(当 运行 从 [=41] 中获取 class 文件时=]) 和内部(使用 Maven 将文件打包成 jar 文件后)。
编辑:我需要代码来处理预打包和 POST- 打包。含义:如果我 运行 a Main.java FROM INSIDE IDE 它将获得资源;如果我将所有内容打包到 JAR 中,然后 运行 JAR 它将获得资源 - 全部使用相同的代码。
使用:Main.class.getResource("/resource.txt")
.
请注意,您尝试使用对 getClassLoader
的任何调用都非常糟糕(它更多的文本,并且会更频繁地失败,因为 class 加载程序在特殊情况下可以为空(具体来说,当你是 bootstrap 加载程序的一部分),而直接在 class 上调用 getResource 始终有效。
您的代码段不起作用的原因是,在 class 加载程序上调用 getResource
时,您不得以斜线开头资源。当直接调用 class 时,你可以(如果你不这样做,它将相对于你正在调用它的 class 的包,如果你这样做,它将是相对于根)。
TL;DR: 在 SomeClass.class.getClassLoader().getResource
、getClass().getResource
和 MyClass.class.getResource
形式中,只有最后一个是正确的,其余的都是次等的,因此根本不应该使用.
Maven 使用了一种叫做 Standard Directory Layout 的东西。如果您不遵循此布局,那么插件将无法正常工作。从技术上讲,您可以将 Maven 配置为使用不同的目录,但在 99.999% 的情况下,这是没有必要的。
此布局的特点之一是生产文件进入:
<project-dir>/src/main/java
- 所有
*.java
个文件
<project-dir>/src/main/resources
- 所有非
*.java
文件(即资源)
当您构建项目时,会编译 Java 源文件并将 *.class
文件放入 target/classes
目录;这是由 maven-compiler-plugin
完成的。同时,资源文件也从src/main/resources
复制到target/classes
; maven-resources-plugin
对此负责。
注:见Introduction to the Build Lifecycle for more information about phases and which plugins are executed by which phase. This Stack Overflow question可能也有用。
当您从 IDE 启动您的应用程序时(可能通过 exec-maven-plugin
)target/classes
目录被放置在类路径中。这意味着来自 src/main/java
的所有已编译 类 和来自 src/main/resources
的所有复制资源都可以通过类路径使用。
然后,当您将应用程序打包到 JAR 文件中时,target/classes
中的所有文件都会添加到生成的 JAR 文件中(由 maven-jar-plugin
处理)。 这包括从 src/main/resources
复制的资源。当您使用此 JAR 文件启动应用程序时,资源仍可通过类路径使用,因为它们嵌入在 JAR 文件中。
要使 resource.txt
在类路径上可用,只需移动:
<project-dir>/resource.txt
收件人:
<project-dir>/src/main/resources/resource.txt.
然后您可以使用 Class#getResource
和 /resource.txt
作为路径,一切都会为您解决。 getResource
返回的 URL
会有所不同,具体取决于您是针对 target/classes
还是针对 JAR 文件执行。
当针对 target/classes
执行时,您会得到如下内容:
file:///.../<project-dir>/target/classes/resource.txt
当针对 JAR 文件执行时,您会得到如下内容:
jar:file:///.../<project-dir>/target/projectname-version.jar!/resource.txt
注意: 这一切都假定 resource.txt
实际上应该是资源而不是外部文件。一旦部署在 JAR 文件中,资源通常 read-only;如果您需要一个可写文件,那么您可以使用该文件的指定位置(例如,用户主目录中的文件夹)。人们通常通过 java.io.File
或 java.nio.file.*
访问外部文件。请记住,资源与普通文件不同。
现在,如果您将 resource.txt
直接放在 <project-dir>
下,那么 对 Maven 毫无意义。它不会被复制到 target/classes
或最终出现在 JAR 文件中,这意味着该资源在类路径上永远不可用。所以重申一下,所有资源都在 src/main/resources
.
下
查看 java.lang.Class#getResource(String)
的 Java 文档以获取有关路径的更多信息,例如何时使用前导 /
以及何时不使用。 link 指向 Javadoc for Java 12,其中包括有关资源和模块的信息(JPMS/Jigsaw 模块,而不是 Maven 模块);如果您不使用模块,则可以忽略文档的那一部分。
当应用程序打包到 jar 中时,我需要从应用程序的根目录中获取资源。我的项目是这样的:
ProjectRoot
resource.txt //want to access from here
src
main
java
package1
package2
package3
Main.java
target
app.jar
classes
resource.txt //works when here
package1
package2
package3
Main.class
我使用这个代码:
Path path = Paths.get("resource.txt");
当 运行 打包成 jar 之前,它发现文件很好(在 ProjectRoot 中)。 运行ning jar 时找不到,将此路径转换为target/resource.txt
.
此代码:
BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
"resource.txt")));
当运行打包前找target/classes
里面的资源。打包后它声称从 .../target/app.jar!/resource.txt
.
此代码:
BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
"/resource.txt")));
我不明白在哪里寻找资源,但它似乎不是ProjectRoot
。
我想要做的就是将资源放在 ProjectRoot
中,并能够从两个外部 jar 访问它(当 运行 从 [=41] 中获取 class 文件时=]) 和内部(使用 Maven 将文件打包成 jar 文件后)。
编辑:我需要代码来处理预打包和 POST- 打包。含义:如果我 运行 a Main.java FROM INSIDE IDE 它将获得资源;如果我将所有内容打包到 JAR 中,然后 运行 JAR 它将获得资源 - 全部使用相同的代码。
使用:Main.class.getResource("/resource.txt")
.
请注意,您尝试使用对 getClassLoader
的任何调用都非常糟糕(它更多的文本,并且会更频繁地失败,因为 class 加载程序在特殊情况下可以为空(具体来说,当你是 bootstrap 加载程序的一部分),而直接在 class 上调用 getResource 始终有效。
您的代码段不起作用的原因是,在 class 加载程序上调用 getResource
时,您不得以斜线开头资源。当直接调用 class 时,你可以(如果你不这样做,它将相对于你正在调用它的 class 的包,如果你这样做,它将是相对于根)。
TL;DR: 在 SomeClass.class.getClassLoader().getResource
、getClass().getResource
和 MyClass.class.getResource
形式中,只有最后一个是正确的,其余的都是次等的,因此根本不应该使用.
Maven 使用了一种叫做 Standard Directory Layout 的东西。如果您不遵循此布局,那么插件将无法正常工作。从技术上讲,您可以将 Maven 配置为使用不同的目录,但在 99.999% 的情况下,这是没有必要的。
此布局的特点之一是生产文件进入:
<project-dir>/src/main/java
- 所有
*.java
个文件
- 所有
<project-dir>/src/main/resources
- 所有非
*.java
文件(即资源)
- 所有非
当您构建项目时,会编译 Java 源文件并将 *.class
文件放入 target/classes
目录;这是由 maven-compiler-plugin
完成的。同时,资源文件也从src/main/resources
复制到target/classes
; maven-resources-plugin
对此负责。
注:见Introduction to the Build Lifecycle for more information about phases and which plugins are executed by which phase. This Stack Overflow question可能也有用。
当您从 IDE 启动您的应用程序时(可能通过 exec-maven-plugin
)target/classes
目录被放置在类路径中。这意味着来自 src/main/java
的所有已编译 类 和来自 src/main/resources
的所有复制资源都可以通过类路径使用。
然后,当您将应用程序打包到 JAR 文件中时,target/classes
中的所有文件都会添加到生成的 JAR 文件中(由 maven-jar-plugin
处理)。 这包括从 src/main/resources
复制的资源。当您使用此 JAR 文件启动应用程序时,资源仍可通过类路径使用,因为它们嵌入在 JAR 文件中。
要使 resource.txt
在类路径上可用,只需移动:
<project-dir>/resource.txt
收件人:
<project-dir>/src/main/resources/resource.txt.
然后您可以使用 Class#getResource
和 /resource.txt
作为路径,一切都会为您解决。 getResource
返回的 URL
会有所不同,具体取决于您是针对 target/classes
还是针对 JAR 文件执行。
当针对 target/classes
执行时,您会得到如下内容:
file:///.../<project-dir>/target/classes/resource.txt
当针对 JAR 文件执行时,您会得到如下内容:
jar:file:///.../<project-dir>/target/projectname-version.jar!/resource.txt
注意: 这一切都假定 resource.txt
实际上应该是资源而不是外部文件。一旦部署在 JAR 文件中,资源通常 read-only;如果您需要一个可写文件,那么您可以使用该文件的指定位置(例如,用户主目录中的文件夹)。人们通常通过 java.io.File
或 java.nio.file.*
访问外部文件。请记住,资源与普通文件不同。
现在,如果您将 resource.txt
直接放在 <project-dir>
下,那么 对 Maven 毫无意义。它不会被复制到 target/classes
或最终出现在 JAR 文件中,这意味着该资源在类路径上永远不可用。所以重申一下,所有资源都在 src/main/resources
.
查看 java.lang.Class#getResource(String)
的 Java 文档以获取有关路径的更多信息,例如何时使用前导 /
以及何时不使用。 link 指向 Javadoc for Java 12,其中包括有关资源和模块的信息(JPMS/Jigsaw 模块,而不是 Maven 模块);如果您不使用模块,则可以忽略文档的那一部分。