getResourceAsStream返回null

Aza*_*Aza 163 java file-io resources

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

/src/initialization/Lifepaths.txt
Run Code Online (Sandbox Code Playgroud)

用于加载文件的代码是:

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

null无论我使用什么,打印输出都会打印出来.我不确定为什么以上都行不通,所以我也尝试过:

  • "/src/initialization/Lifepaths.txt"
  • "initialization/Lifepaths.txt"
  • "Lifepaths.txt"

这些都不奏效. 了许多 问题至今的话题,但他们都不是有帮助的-通常情况下,他们只是说来加载使用根路径,这我已经在做的文件.那,或者只是从当前目录加载文件(只是加载filename),我也尝试过.该文件正在具有适当名称的适当位置编译到JAR中.

我该如何解决这个问题?

hoa*_*oaz 145

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

Lifepaths.class.getResourceAsStream(...) 使用加载Lifepaths类的相同类加载器加载资源,它应该可以访问JAR中的资源

  • 只是为了添加,当调用getResourceAsStream(name)时,名称必须以"/"开头.我不确定这是否必要,但没有它我就有问题. (99认同)
  • 从昨天早上8点开始,我一直在搞这个.救了我.我也需要一个领先的斜线来使它工作. (3认同)
  • 还要记住,所需的源可以在包层次结构之外.在这种情况下,您必须在路径中使用"../"以获得一个级别,然后使用另一个路径分支来访问您的资源. (3认同)
  • 仅添加一些信息,如果文件位于其他目录下,则需要在路径前添加`/`。例如`initialization / Lifepaths.txt`。如果文件的路径与yout类的相同(但在资源作为主目录)下,则可以仅放置文件名,而不添加任何/。例如,如果您的类具有以下路径`src / main / java / paths / Lifepaths.java`,则文件必须具有该路径`src / main / resources / paths / Lifepaths.txt`。 (3认同)
  • @David-我认为(以'/'开头)是必须的,否则它将相对于Lifepaths.class包进行搜索 (2认同)
  • @Zartc 这不是文件访问,它的 jar 访问是 Java Archive - 我花了相当多的时间弄清楚我的 IDE 在做什么,而我没有,非常感谢这篇文章。很多人在没有 ide 的情况下使用文本编辑器或 ipython 进行 js/python 开发。 (2认同)
  • 我同意@DaveAnkin 的观点,这是 Java 的另一个领域,它绝对是一团糟,而且是一场彻头彻尾的噩梦。其他平台绝对不会遭受这种可以避免的复杂性的困扰。 (2认同)

Puc*_*uce 55

规则如下:

  1. 检查要在JAR中加载的文件的位置(从而确保它实际添加到JAR中)
  2. 使用绝对路径:路径从JAR的根开始
  3. 使用相对路径:path从你正在调用的类的包目录开始getResource/getResoucreAsStream

并尝试:

Lifepaths.class.getResourceAsStream("/initialization/Lifepaths.txt")
Run Code Online (Sandbox Code Playgroud)

代替

Lifepaths.class.getClass().getResourceAsStream("/initialization/Lifepaths.txt")
Run Code Online (Sandbox Code Playgroud)

(不确定它是否有所作为,但前者将使用正确的ClassLoader/JAR,而我不确定后者)

  • 我已经完成了这三件事。请重读我的问题。 (2认同)

gre*_*dha 44

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

我所看到的最好的解释是来自JavaWorld的这篇文章.我将在这里总结,但如果你想了解更多,你应该查看这篇文章.

方法

1)ClassLoader.getResourceAsStream().

格式:"/" - 分隔名称; 没有前导"/"(所有名称都是绝对的).

例: this.getClass().getClassLoader().getResourceAsStream("some/pkg/resource.properties");

2) Class.getResourceAsStream()

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

例: this.getClass().getResourceAsStream("/some/pkg/resource.properties");


Pau*_*ith 14

不要使用绝对路径,使它们相对于项目中的"resources"目录.快速而脏的代码,显示目录"resources"中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);
}
Run Code Online (Sandbox Code Playgroud)


MrD*_*MrD 9

您可能想尝试这个来获取流,即首先获取URL,然后将其作为流打开.

URL url = getClass().getResource("/initialization/Lifepaths.txt"); 
InputStream strm = url.openStream(); 
Run Code Online (Sandbox Code Playgroud)

我曾经有一个类似的问题:从jar读取txt文件失败但读取图像有效

  • 这正是getResourceAsStream()所做的 (2认同)

plo*_*sco 9

我发现自己遇到了类似的问题。由于我使用的是 maven,因此我需要更新我的 pom.xml 以包含如下内容:

   ...
</dependencies>
<build>
    <resources>
        <resource>
            <directory>/src/main/resources</directory>
        </resource>
        <resource>
            <directory>../src/main/resources</directory>
        </resource>
    </resources>
    <pluginManagement>
        ...
Run Code Online (Sandbox Code Playgroud)

请注意其中的资源标签以指定该文件夹的位置。如果您有嵌套项目(就像我一样),那么您可能希望从其他区域获取资源,而不仅仅是在您正在使用的模块中。如果您使用类似的配置数据,这有助于减少在每个 repo 中保留相同的文件


Bin*_*ati 7

您正在使用的ClassLoader似乎存在问题.使用contextClassLoader加载类.这与它是否采用静态/非静态方法无关

Thread.currentThread().getContextClassLoader().getResourceAsStream......


Rid*_*dox 5

默认的 JVM 类加载器将首先使用父类加载器加载资源: 删除门父类加载器

Lifepaths.class.getClass()的类加载器是bootstrap classloader,因此getResourceAsStream将仅搜索 $JAVA_HOME ,无论用户提供什么classpath。显然,Lifepaths.txt 不存在。

Lifepaths.class的类加载器是system classpath classloader,因此getResourceAsStream将搜索用户定义的classpath并且 Lifepaths.txt 就在那里。

使用 时,将添加不以“/”java.lang.Class#getResourceAsStream(String name)开头的名称作为前缀。为了避免这种情况使用。package namejava.lang.ClassLoader#getResourceAsStream

例如:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
String resourceName = "Lifepaths.txt";
InputStream resourceStream = loader.getResourceAsStream(resourceName); 
Run Code Online (Sandbox Code Playgroud)


Shi*_* Lv 5

大致说来:

getClass().getResource("/") ~= Thread.currentThread().getContextClassLoader().getResource(".")

假设您的项目结构如下所示:

??? src
?   ??? main
?   ??? test
?   ??? test
?       ??? java
?       ?   ??? com
?       ?       ??? github
?       ?           ??? xyz
?       ?               ??? proj
?       ?                   ??? MainTest.java
?       ?                   ??? TestBase.java
?       ??? resources
?           ??? abcd.txt
??? target
    ??? test-classes
        ??? com
        ??? abcd.txt

Run Code Online (Sandbox Code Playgroud)
// in MainClass.java
this.getClass.getResource("/") -> "~/proj_dir/target/test-classes/"
this.getClass.getResource(".") -> "~/proj_dir/target/test-classes/com/github/xyz/proj/"
Thread.currentThread().getContextClassLoader().getResources(".") -> "~/proj_dir/target/test-classes/"
Thread.currentThread().getContextClassLoader().getResources("/") ->  null

Run Code Online (Sandbox Code Playgroud)