为什么在JDK 11中getResource()方法返回null?

Ale*_*xey 4 java java-11

简单的Java程序:

public static String loadText(String file) {
    StringBuilder finalString = new StringBuilder();

    InputStream in = null;
    BufferedReader reader = null;
    InputStreamReader isr = null;

    try{
        System.out.println("Text File: " + file);

        // Version 1
        //URL url = Thread.currentThread().getClass().getResource(file); 
        //in = url.openStream();

        // Version 2
        in = Class.class.getResourceAsStream(file);

        isr = new InputStreamReader(in);
        reader = new BufferedReader(isr);
        String line;
        while((line = reader.readLine()) != null) {
            finalString.append(line).append("//\n");
        }
    }
    catch(IOException e) {
        e.printStackTrace();
        System.exit(-1);
    }
    finally {
        try {
            if (isr != null) { isr.close(); }
            if (reader != null) { reader.close(); }
            if (in != null) { in.close(); }
            } catch (IOException e) { e.printStackTrace(); }
        }
    return finalString.toString();
}
Run Code Online (Sandbox Code Playgroud)

getResourcegetResourceAsStream在JDK 8(java的8 OpenJDK的-AMD64)方法工作正常,但总是返回null在JDK 11。

问题:为什么?我该如何解决呢?

  • 操作系统:Linux Mint 19 Tara x64
  • IDE:Eclipse 2018年12月(4.10.0)

Sve*_*rev 7

我已经在MacOS上同时使用openjdk 8和11尝试了您的应用程序,但不能同时使用它们。我认为您需要查看[1]和[2]才能了解其getResourceAsStream工作原理。

TLDR:

  1. 如果路径是绝对路径(即以斜杠-开头/),则class.getResourceAsStream()在提供的路径中搜索

  2. 如果该路径不是绝对路径(即不是以斜杠开头),则class.getResourceAsStream()在与包名称相对应的构造路径中搜索,其中点用斜杠替换

因此,是否起作用取决于两件事:

  1. 您的路径是否绝对?
  2. 是否与file课程位于同一包中?

基本上在您提供的示例中,如果路径不是绝对路径,它将永远无法工作,因为Class.class.getResourceAsStream()它将始终解析到的路径java/lang/<file>,因此您的文件必须位于系统软件包中。因此,您必须使用<MyClass>.class.getResourceAsStream()或替代地使用绝对路径

[1] https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#getResource(java.lang.String)

[2] https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getResource%28java.lang.String%29


更新资料

从Java SE 9开始,在命名模块中的类上调用getResourceXXX只会在该模块中找到资源,因此不会像在先前版本中那样搜索类路径。因此,当您使用Class.class.getResourceAsStream()它时,它将尝试在包含java.lang.Classjava.base模块(即模块)中定位资源。显然,您的资源不在该模块中,因此它返回null。

您必须使Java 9+在模块中搜索文件,该文件很可能是“未命名的模块”。您可以通过更改Class为模块中定义的任何类来做到这一点,以使java使用正确的类加载器。


j12*_*567 7

还有另一种解决方案使用ClassLoader

ClassLoader.getSystemResourceAsStream(file)
Run Code Online (Sandbox Code Playgroud)

从所有位置加载。SomeClass我用它从 JAR 文件加载资源,该文件只包含资源,没有可执行代码,因此前面的技巧无法工作,因为JAR 中没有可做的事情SomeClass.class.getResourceAsStream()

我只是不了解内部结构,我还必须更改文件的路径。

我的 JAR 文件位于 JAR 存档的根目录中,其中包含文件“my-file.txt”。

对于 java 8,这有效

Class.class.getResourceAsStream("/my-file.txt");
Run Code Online (Sandbox Code Playgroud)

/对于 java 11,即使文件位于根路径中,我也必须删除前导

ClassLoader.getSystemResourceAsStream("my-file.txt");
Run Code Online (Sandbox Code Playgroud)