检索子包类的资源

fuk*_*uri 7 java packages directory-structure getresource

我没有长时间使用java,所以我不确定还有什么要寻找的.我希望有人可以指出我正确的方向.

目标: 我想使用查找表,存储为文本文件.但我不想使用绝对路径,因为最后我想打包一个版本并能够从任何位置调用它(文本文件将包含在打包版本中).

当前设置: 我将文本文件放在一个名为"resources"的文件夹中(因为从阅读有关java的教程,我得到了印象,这是我应该把它用来维护一个更好的结构化项目).

在根包文件夹中,我有一个类(MainClass.java),它在子包中调用另一个类(LookUpClass.java).文件夹设置如下:

  • SRC
    • java的
      • main.package.com
        • 分装
          • LookUpClass.java
          • PlotterClass.java
        • MainClass.java
    • 资源
      • 查找表
        • LookUpTable1.txt
        • LookUpTable2.txt

我写了一个方法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;
}
Run Code Online (Sandbox Code Playgroud)

在我的项目结构中,"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);
}
Run Code Online (Sandbox Code Playgroud)

输出:

Color of line 5: 0  0   38
Run Code Online (Sandbox Code Playgroud)

(哪个是对的.)

我添加了完全相同的行PlotterClass.java,它也工作正常.

问题:

现在,如果我尝试相同,MainClass.java我得到一个错误,url为null.似乎无法找到资源/资源文件夹.

我已经阅读了SO上的各种帖子,并尝试了几个提议的解决方案,到目前为止都失败了:

  • 如果使用LookUpClass.class.getClassLoader().getResource("/LookUpTables/LookUpTable1.txt")from MainClass.javaLookUpClass.javafail 两个调用(url为null).
  • 我尝试使用以下路径(所有不在任何一个类中工作):"LookUpTables/LookUpTable1.txt"(删除开始"/")"/ subpackage/LookUpTables/LightsUpTable1.txt""../subpackage/LookUpTables/LightsUpTable1.文本"
  • 自从使用Idea IntelliJ以来,我检查了"设置>构建,执行,部署>计算机>资源模式"并在模式中添加了"*.txt".没有改变.
  • 如果添加Class c = LookUpClass.class.getClass();,在调试模式c中是"class.java.lang.Class".我期待像"main.package.com.subpackage.LookUpClass"这样的东西.
  • 在某些时候我尝试使用getResourceAsStream(),但我不明白如何获得我的(例如)第5行,所以我放弃了它.如果它解决了我的问题,我愿意读这个.

我不知道如何解决这个问题.而且我意识到,在这一点上,我只是在尝试一些事情,甚至不理解为什么它可以或不可行.对我来说,它似乎LookUpClass.java只是从不同的位置运行MainClass.java.但"资源"文件夹和相应的文本文件位置永远不会改变.如何在一个案例中找到该文件,而在另一个案例中却找不到?

See*_*ose 3

Maven 有一个标准的目录布局。该目录src/main/resources适用于此类应用程序资源。将您的文本文件放入其中。

现在,您基本上有两个选择来准确放置文件:

  1. 资源文件属于一个类。

一个示例是表示 GUI 元素(面板)的类,该元素还需要显示一些图像。

在这种情况下,将资源文件放入与相应类相同的目录(包)中。例如,对于名为的类,your.pkg.YourClass将资源文件放入目录中your/pkg

src/main
 +-- java/
 |    +-- your/pkg/
 |    |    +-- YourClass.java
 +-- resources/
      +-- your/pkg/
           +-- resource-file.txt
Run Code Online (Sandbox Code Playgroud)

现在,您可以通过相应的类加载资源。在类中,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
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:您还可以通过类的类加载器加载资源:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

选择您觉得更方便的。

  1. 该资源完全属于应用程序。

在这种情况下,只需将资源直接放入src/main/resources目录或适当的子目录中即可。让我们看一下查找文件的示例:

src/main/resources/
    +-- LookupTables/
         +-- LookUpTable1.txt
Run Code Online (Sandbox Code Playgroud)

然后,您必须通过类加载器加载资源,使用当前线程的上下文类加载器或应用程序类加载器(无论哪种更合适 - 如果感兴趣,请搜索有关此问题的文章)。我将向您展示两种方法:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

作为第一个建议,使用当前线程的上下文类加载器。在独立应用程序中,这将是系统类加载器或将系统类加载器作为父级。(这些类加载器之间的区别对于也加载资源的库来说变得很重要。)

您应该始终使用类加载器来加载资源。通过这种方式,您可以使加载独立于位置(只需注意启动应用程序时文件位于类路径内),并且您可以将整个应用程序打包到仍然可以找到资源的 JAR 文件中。