我没有长时间使用java,所以我不确定还有什么要寻找的。我希望有人能指出我正确的方向。
目标: 我想使用一个查找表,存储为文本文件。但我不想使用绝对路径,因为最后我想打包一个版本并能够从任何位置调用它(文本文件将包含在打包版本中)。
当前设置: 我把文本文件放在一个名为“resources”的文件夹中(因为从阅读有关java的教程,我得到的印象是,这是我应该把它用于维护更好的结构化项目的地方)。
在根包文件夹中,我有一个类(MainClass.java),它在子包中调用另一个类(LookUpClass.java)。 文件夹设置如下:
我在LookUpClass.java
中编写了一个方法,该方法从资源中的查找表中检索某一行。要检索文件并读出某一行,我使用了
// 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
为空的错误。似乎无法找到资源/资源文件夹。
我已经阅读了关于SO的各种帖子,并尝试了几个提议的解决方案,到目前为止都失败了:
LookUpClass.class.getClassLoader().getResource("/LookUpTables/LookUpTable1.txt")
来自MainClass.java
和LookUpClass.java
的两次通话都失败(url
为空)。Class c = LookUpClass.class.getClass();
,则在调试模式c中为“class.java.lang.Class”。我期待像“main.package.com.subpackage.LookUpClass”这样的东西。getResourceAsStream()
,但我不明白如何获得我的(例如)第5行,所以我放弃了它。如果它解决了我的问题,我愿意读这个。我不知道如何解决这个问题。而且我意识到,在这一点上,我只是在尝试一些事情,甚至不理解为什么它可以或不可行。
对我而言,似乎LookUpClass.java
来自与MainClass.java
不同的位置。但“资源”文件夹和相应的文本文件位置永远不会改变。如何在一个案例中找到该文件,而在另一个案例中却找不到?
答案 0 :(得分:2)
Maven有一个standard directory layout。目录src/main/resources
适用于此类应用程序资源。将文本文件放入其中。
您现在基本上有两个选项可以放置文件:
这方面的一个例子是一个表示需要同时显示一些图像的GUI元素(面板)的类。
在这种情况下,将资源文件放在与相应类相同的目录(包)中。例如。对于名为your.pkg.YourClass
的类,将资源文件放入目录your/pkg
:
src/main
+-- java/
| +-- your/pkg/
| | +-- YourClass.java
+-- resources/
+-- your/pkg/
+-- resource-file.txt
您现在通过相应的类加载资源。在课程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 loader:
加载资源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
然后,您必须通过类加载器加载资源,使用当前线程的上下文类加载器或应用程序类加载器(更合适的是 - 如果感兴趣,请搜索有关此问题的文章)。我会告诉你两种方式:
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
}
}
作为第一个建议,使用当前线程的上下文类加载器。在独立应用程序中,这将是系统类加载器或将系统类加载器作为父级。 (这些类加载器之间的区别对于同时加载资源的库也很重要。)
您应该始终使用类加载器来加载资源。这样,您可以独立于该位置进行加载(只需在启动应用程序时注意文件位于类路径内),并且可以将整个应用程序打包到仍然可以找到资源的JAR文件中。
答案 1 :(得分:0)
考虑到您提供的MWE,我试图重现您的问题,但没有成功。我在这里上传了我的项目,包括一个pom.xml(你提到你使用了maven):http://www.filedropper.com/stackoverflow 这就是我的查找类的样子(也展示了如何使用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;
}
}