正在检索子包的资源 class
Retrieving resources for a subpackage class
我使用 java 的时间不长,所以我不确定还需要寻找什么。我希望有人能给我指出正确的方向。
目标:
我想使用查找 table,存储为文本文件。但我不想使用绝对路径,因为最后我想打包一个版本并能够从任何位置调用它(文本文件将包含在打包版本中)。
当前设置:
我将文本文件放在一个名为 "resources" 的文件夹中(因为通过阅读有关 java 的教程,我得到的印象是,我应该把它放在这里以维护结构更好的项目)。
在根包文件夹中,我有一个 class (MainClass.java) 在子包中调用另一个 class (LookUpClass.java)。
文件夹设置如下:
- 来源
- java
- main.package.com
- 分包
- LookUpClass.java
- PlotterClass.java
- MainClass.java
- 资源
- 查找表
- LookUpTable1.txt
- LookUpTable2.txt
我在 LookUpClass.java
中写了一个方法,它从我在资源中的查找 table 中检索某一行。为了检索文件并读出某一行,我使用了
// Gets respective line from LUT
private static String getLineFromLUT(int line) {
URL url = LookUpClass.class.getClass().getResource("/LookUpTables/LookUpTable1.txt");
File file = new File(url.toURI());
BufferedReader br = new BufferedReader(new FileReader(file));
for (int i = 0; i < line; ++i)
br.readLine();
return br.readLine;
}
在我的项目结构中,"java" 文件夹被标记为 "source",而 "resources" 被标记为 "resources"。
我的测试设置非常简单:
public static void main(String[] args) throws URISyntaxException, IOException {
String c = LookUpClass.getLineFromLUT(5);
System.out.println("Color of line 5: " + c);
}
输出:
Color of line 5: 0 0 38
(正确。)
我向 PlotterClass.java
添加了完全相同的行,它也工作正常。
问题:
现在,如果我在 MainClass.java
中尝试相同的操作,我会收到 url
为空的错误。似乎找不到 resource/resource 文件夹。
我已经阅读了关于 SO 的各种帖子并尝试了几个建议的解决方案,但到目前为止都失败了:
- 如果使用
LookUpClass.class.getClassLoader().getResource("/LookUpTables/LookUpTable1.txt")
来自 MainClass.java
和 LookUpClass.java
的调用都失败(url
为空)。
- 我尝试使用以下路径(在 classes 中都不起作用):
"LookUpTables/LookUpTable1.txt"(删除开头的“/”)
“/subpackage/LookUpTables/LookUpTable1.txt”
"../subpackage/LookUpTables/LookUpTable1.txt"
- 自从使用 Idea IntelliJ 以来,我检查了 "Settings > Build, Execution, Deployment > Compiter > Resource patterns" 并在模式中添加了“*.txt”。没有任何变化。
- 如果加上
Class c = LookUpClass.class.getClass();
,Debug模式下c为"class.java.lang.Class"。我期待 "main.package.com.subpackage.LookUpClass".
- 有时我尝试使用
getResourceAsStream()
,但我不明白如何获得我的(例如)第 5 行,所以我放弃了它。如果它能解决我的问题,我愿意继续阅读。
我不知道如何解决这个问题。我意识到在这一点上我只是在尝试一些东西,甚至不明白为什么它可以或不能工作。
对我来说,似乎 LookUpClass.java
与 MainClass.java
来自不同的位置 运行。但是 "resources" 文件夹和相应的文本文件位置永远不会改变。怎么会一种情况下找到文件,另一种情况下找不到?
根据您提供的 MWE,我尝试重现您的问题,但没有成功。我在此处上传了我的项目,其中包括 pom.xml(您提到您使用了 maven):http://www.filedropper.com/Whosebug
这是我的查找 class 的样子(还展示了如何使用 getResourceAsStream 方法):
public class LookUpClass {
final static String tableName = "resources/LookUpTables/LookUpTable1.txt";
public static String getLineFromLUT(final int line) {
final URL url = LookUpClass.class.getResource(tableName);
if (url.toString().startsWith("jar:")) {
try (final URLClassLoader loader = URLClassLoader
.newInstance(new URL[] { url })) {
return getLineFromLUT(
new InputStreamReader(
loader.getResourceAsStream(tableName)), line);
} catch (final IOException e) {
e.printStackTrace();
}
} else {
return getLineFromLUT(
new InputStreamReader(
LookUpClass.class.getResourceAsStream(tableName)),
line);
}
return null;
}
public static String getLineFromLUT(final Reader reader, final int line) {
try (final BufferedReader br = new BufferedReader(reader)) {
for (int i = 0; i < line; ++i)
br.readLine();
return br.readLine();
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
}
Maven 有一个 standard directory layout。目录 src/main/resources
用于此类应用程序资源。将您的文本文件放入其中。
您现在基本上有两个选项可以准确地放置您的文件:
- 资源文件属于class。
一个例子是 class 代表一个 GUI 元素(一个面板),它也需要显示一些图像。
在这种情况下,将资源文件放入与相应class相同的目录(包)中。例如。对于名为 your.pkg.YourClass
的 class 将资源文件放入目录 your/pkg
:
src/main
+-- java/
| +-- your/pkg/
| | +-- YourClass.java
+-- resources/
+-- your/pkg/
+-- resource-file.txt
您现在通过相应的 class 加载资源。在 class your.pkg.YourClass
中,您有以下用于加载的代码片段:
String resource = "resource-file.txt"; // the "file name" without any package or directory
Class<?> clazz = this.getClass(); // or YourClass.class
URL resourceUrl = clazz.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
注意:您也可以通过 class' class 加载程序加载资源:
String resource = "your/pkg/resource-file.txt";
ClassLoader loader = this.getClass().getClassLoader(); // or YourClass.class.getClassLoader()
URL resourceUrl = loader.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
选择,你觉得更方便。
- 资源属于应用整体。
在这种情况下,只需将资源直接放入 src/main/resources
目录或适当的子目录即可。让我们看一下您的查找文件的示例:
src/main/resources/
+-- LookupTables/
+-- LookUpTable1.txt
然后您必须通过 class 加载器加载资源,使用当前线程的上下文 class 加载器或应用程序 class 加载器(无论哪个更合适 - 去搜索有关此问题的文章,如果有兴趣)。我会告诉你两种方式:
String resource = "LookupTables/LookUpTable1.txt";
ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
URL resourceUrl = ctxLoader.getResource(resource); // or sysLoader.getResource(resource)
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
作为第一个建议,使用当前线程的上下文 class 加载器。在独立应用程序中,这将是系统 class 加载程序或将系统 class 加载程序作为父级。 (这些 class 加载器之间的区别对于同时加载资源的库来说很重要。)
您应该始终使用 class 加载程序来加载资源。通过这种方式,您可以独立于位置进行加载(只需注意文件在启动应用程序时位于 class 路径内)并且您可以将整个应用程序打包到一个仍然可以找到资源的 JAR 文件中。
我使用 java 的时间不长,所以我不确定还需要寻找什么。我希望有人能给我指出正确的方向。
目标: 我想使用查找 table,存储为文本文件。但我不想使用绝对路径,因为最后我想打包一个版本并能够从任何位置调用它(文本文件将包含在打包版本中)。
当前设置: 我将文本文件放在一个名为 "resources" 的文件夹中(因为通过阅读有关 java 的教程,我得到的印象是,我应该把它放在这里以维护结构更好的项目)。
在根包文件夹中,我有一个 class (MainClass.java) 在子包中调用另一个 class (LookUpClass.java)。 文件夹设置如下:
- 来源
- java
- main.package.com
- 分包
- LookUpClass.java
- PlotterClass.java
- MainClass.java
- 分包
- main.package.com
- 资源
- 查找表
- LookUpTable1.txt
- LookUpTable2.txt
- 查找表
- java
我在 LookUpClass.java
中写了一个方法,它从我在资源中的查找 table 中检索某一行。为了检索文件并读出某一行,我使用了
// Gets respective line from LUT
private static String getLineFromLUT(int line) {
URL url = LookUpClass.class.getClass().getResource("/LookUpTables/LookUpTable1.txt");
File file = new File(url.toURI());
BufferedReader br = new BufferedReader(new FileReader(file));
for (int i = 0; i < line; ++i)
br.readLine();
return br.readLine;
}
在我的项目结构中,"java" 文件夹被标记为 "source",而 "resources" 被标记为 "resources"。
我的测试设置非常简单:
public static void main(String[] args) throws URISyntaxException, IOException {
String c = LookUpClass.getLineFromLUT(5);
System.out.println("Color of line 5: " + c);
}
输出:
Color of line 5: 0 0 38
(正确。)
我向 PlotterClass.java
添加了完全相同的行,它也工作正常。
问题:
现在,如果我在 MainClass.java
中尝试相同的操作,我会收到 url
为空的错误。似乎找不到 resource/resource 文件夹。
我已经阅读了关于 SO 的各种帖子并尝试了几个建议的解决方案,但到目前为止都失败了:
- 如果使用
LookUpClass.class.getClassLoader().getResource("/LookUpTables/LookUpTable1.txt")
来自MainClass.java
和LookUpClass.java
的调用都失败(url
为空)。 - 我尝试使用以下路径(在 classes 中都不起作用): "LookUpTables/LookUpTable1.txt"(删除开头的“/”) “/subpackage/LookUpTables/LookUpTable1.txt” "../subpackage/LookUpTables/LookUpTable1.txt"
- 自从使用 Idea IntelliJ 以来,我检查了 "Settings > Build, Execution, Deployment > Compiter > Resource patterns" 并在模式中添加了“*.txt”。没有任何变化。
- 如果加上
Class c = LookUpClass.class.getClass();
,Debug模式下c为"class.java.lang.Class"。我期待 "main.package.com.subpackage.LookUpClass". - 有时我尝试使用
getResourceAsStream()
,但我不明白如何获得我的(例如)第 5 行,所以我放弃了它。如果它能解决我的问题,我愿意继续阅读。
我不知道如何解决这个问题。我意识到在这一点上我只是在尝试一些东西,甚至不明白为什么它可以或不能工作。
对我来说,似乎 LookUpClass.java
与 MainClass.java
来自不同的位置 运行。但是 "resources" 文件夹和相应的文本文件位置永远不会改变。怎么会一种情况下找到文件,另一种情况下找不到?
根据您提供的 MWE,我尝试重现您的问题,但没有成功。我在此处上传了我的项目,其中包括 pom.xml(您提到您使用了 maven):http://www.filedropper.com/Whosebug 这是我的查找 class 的样子(还展示了如何使用 getResourceAsStream 方法):
public class LookUpClass {
final static String tableName = "resources/LookUpTables/LookUpTable1.txt";
public static String getLineFromLUT(final int line) {
final URL url = LookUpClass.class.getResource(tableName);
if (url.toString().startsWith("jar:")) {
try (final URLClassLoader loader = URLClassLoader
.newInstance(new URL[] { url })) {
return getLineFromLUT(
new InputStreamReader(
loader.getResourceAsStream(tableName)), line);
} catch (final IOException e) {
e.printStackTrace();
}
} else {
return getLineFromLUT(
new InputStreamReader(
LookUpClass.class.getResourceAsStream(tableName)),
line);
}
return null;
}
public static String getLineFromLUT(final Reader reader, final int line) {
try (final BufferedReader br = new BufferedReader(reader)) {
for (int i = 0; i < line; ++i)
br.readLine();
return br.readLine();
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
}
Maven 有一个 standard directory layout。目录 src/main/resources
用于此类应用程序资源。将您的文本文件放入其中。
您现在基本上有两个选项可以准确地放置您的文件:
- 资源文件属于class。
一个例子是 class 代表一个 GUI 元素(一个面板),它也需要显示一些图像。
在这种情况下,将资源文件放入与相应class相同的目录(包)中。例如。对于名为 your.pkg.YourClass
的 class 将资源文件放入目录 your/pkg
:
src/main
+-- java/
| +-- your/pkg/
| | +-- YourClass.java
+-- resources/
+-- your/pkg/
+-- resource-file.txt
您现在通过相应的 class 加载资源。在 class your.pkg.YourClass
中,您有以下用于加载的代码片段:
String resource = "resource-file.txt"; // the "file name" without any package or directory
Class<?> clazz = this.getClass(); // or YourClass.class
URL resourceUrl = clazz.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
注意:您也可以通过 class' class 加载程序加载资源:
String resource = "your/pkg/resource-file.txt";
ClassLoader loader = this.getClass().getClassLoader(); // or YourClass.class.getClassLoader()
URL resourceUrl = loader.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
选择,你觉得更方便。
- 资源属于应用整体。
在这种情况下,只需将资源直接放入 src/main/resources
目录或适当的子目录即可。让我们看一下您的查找文件的示例:
src/main/resources/
+-- LookupTables/
+-- LookUpTable1.txt
然后您必须通过 class 加载器加载资源,使用当前线程的上下文 class 加载器或应用程序 class 加载器(无论哪个更合适 - 去搜索有关此问题的文章,如果有兴趣)。我会告诉你两种方式:
String resource = "LookupTables/LookUpTable1.txt";
ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
URL resourceUrl = ctxLoader.getResource(resource); // or sysLoader.getResource(resource)
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
作为第一个建议,使用当前线程的上下文 class 加载器。在独立应用程序中,这将是系统 class 加载程序或将系统 class 加载程序作为父级。 (这些 class 加载器之间的区别对于同时加载资源的库来说很重要。)
您应该始终使用 class 加载程序来加载资源。通过这种方式,您可以独立于位置进行加载(只需注意文件在启动应用程序时位于 class 路径内)并且您可以将整个应用程序打包到一个仍然可以找到资源的 JAR 文件中。