我正在从我的Java项目的编译JAR中的包中加载一个文本文件。相关目录结构如下:

/src/initialization/Lifepaths.txt

我的代码通过调用Class::getResourceAsStream来返回一个InputStream来加载一个文件。

public class Lifepaths {
    public static void execute() {
        System.out.println(Lifepaths.class.getClass().
            getResourceAsStream("/initialization/Lifepaths.txt"));
    }

    private Lifepaths() {}

    //This is temporary; will eventually be called from outside
    public static void main(String[] args) {execute();}
}

不管我用什么,输出总是输出null。我不知道为什么上面的方法不管用,所以我也尝试了一下:

“初始化/ src / / Lifepaths.txt” “初始化/ Lifepaths.txt” “Lifepaths.txt”

这两种方法都不起作用。到目前为止,我已经阅读了许多关于这个主题的问题,但没有一个是有帮助的——通常,他们只是说使用根路径加载文件,而我已经这样做了。或者只是从当前目录加载文件(只是加载文件名),我也尝试过。该文件将被编译到JAR中的适当位置,并具有适当的名称。

我怎么解决这个问题?


当前回答

如果您使用Maven,请确保您的包装是“jar”而不是“pom”。

<packaging>jar</packaging>

其他回答

不要使用绝对路径,让它们相对于项目中的“资源”目录。快速和肮脏的代码,显示MyTest.txt的内容从目录“资源”。

@Test
public void testDefaultResource() {
    // can we see default resources
    BufferedInputStream result = (BufferedInputStream) 
         Config.class.getClassLoader().getResourceAsStream("MyTest.txt");
    byte [] b = new byte[256];
    int val = 0;
    String txt = null;
    do {
        try {
            val = result.read(b);
            if (val > 0) {
                txt += new String(b, 0, val);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } 
    } while (val > -1);
    System.out.println(txt);
}

我知道这里有不同的答案。我的工作是这样的。 资源目录下新增文件。 在可执行代码中,我提到了该文件的路径,在文件名的引号中以“/”作为前缀。

 InputStream resourceStream = loader.getResourceAsStream("/LifePaths.txt");

Lifepaths.class.getClass().getResourceAsStream(…)使用系统类加载器加载资源,它显然失败了,因为它看不到你的jar

getresourceasstream(…)使用与加载Lifepaths类相同的类加载器加载资源,它应该可以访问jar中的资源

因此,从jar中获取资源有几种方法,每种方法的语法略有不同,需要指定不同的路径。

我所看到的最好的解释是来自InfoWorld的这篇文章。我在这里总结一下,但如果你想了解更多,你应该看看这篇文章。

方法

ClassLoader.getResourceAsStream()。

格式:“/”-以名称分隔;没有前导“/”(所有名称都是绝对的)。

例如:this.getClass () .getClassLoader () .getResourceAsStream(“一些/ pkg / resource.properties”);

Class.getResourceAsStream ()

格式:“/”-以名称分隔;前导“/”表示绝对名称;所有其他名称都是相对于类的包

例如:this.getClass () .getResourceAsStream(" /一些/ pkg / resource.properties”);

2020年9月更新:更改文章链接。原文来自Javaworld,它现在托管在InfoWorld上(并且有更多广告)

jdk >=9 needs to open non-root/non-co-parent packages to it in the module-info module.

JDK >=9需要在module-info.java中打开资源目录,例如:

src java resoureces 相依 json log4j2.xml openapi.yaml

如果需要读取conf/config。Json,你需要两个步骤:

// in module-info.java
module your.mod.name {
    open conf;
}

// then in java code
getClassLoader().getResourceAsStream("conf/config.json");

否则,如果你需要在根目录下读取other,它只是:

getClassLoader().getResourceAsStream("openapi.yaml");

你可以看到{@link java.lang.ClassLoader#getResourceAsStream(String)}知道为什么~