简体   繁体   English

getResourceAsStream 返回 null

[英]getResourceAsStream returns null

I'm loading a text file from within a package in a compiled JAR of my Java project.我正在从我的 Java 项目的已编译 JAR 中的 package 中加载一个文本文件。 The relevant directory structure is as follows:相关目录结构如下:

/src/initialization/Lifepaths.txt

My code loads a file by calling Class::getResourceAsStream to return a InputStream .我的代码通过调用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();}
}

The print out will always print null , no matter what I use.打印输出将始终打印null ,无论我使用什么。 I'm not sure why the above wouldn't work, so I've also tried:我不确定为什么上面的方法不起作用,所以我也试过:

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

Neither of these work.这些都不起作用。 I've read numerous questions so far on the topic, but none of them have been helpful - usually, they just say to load files using the root path, which I'm already doing.到目前为止, 我已经阅读了很多关于该主题的问题,但没有一个有帮助 - 通常,他们只是说使用根路径加载文件,我已经在这样做了。 That, or just load the file from the current directory (just load filename ), which I've also tried.那,或者只是从当前目录加载文件(只是加载filename ),我也试过。 The file is being compiled into the JAR in the appropriate location with the appropriate name.该文件正在以适当的名称在适当的位置编译到 JAR。

How do I solve this?我该如何解决这个问题?

Lifepaths.class.getClass().getResourceAsStream(...) loads resources using system class loader, it obviously fails because it does not see your JARs Lifepaths.class.getClass().getResourceAsStream(...)使用系统类加载器加载资源,它显然失败了,因为它看不到你的 JAR

Lifepaths.class.getResourceAsStream(...) loads resources using the same class loader that loaded Lifepaths class and it should have access to resources in your JARs Lifepaths.class.getResourceAsStream(...)使用加载 Lifepaths 类的相同类加载器加载资源,它应该可以访问 JAR 中的资源

The rules are as follows:规则如下:

  1. check the location of the file you want to load inside the JAR (and thus also make sure it actually added to the JAR)检查要加载到 JAR 中的文件的位置(从而确保它确实添加到了 JAR 中)
  2. use either an absolute path: path starts at the root of the JAR使用绝对路径:路径从 JAR 的根开始
  3. use an relative path: path starts at the package directory of the class you're calling getResource/ getResoucreAsStream使用相对路径:路径从您正在调用的类的包目录开始 getResource/getResoucreAsStream

And try:并尝试:

Lifepaths.class.getResourceAsStream("/initialization/Lifepaths.txt")

instead of代替

Lifepaths.class.getClass().getResourceAsStream("/initialization/Lifepaths.txt")

(not sure if it makes a difference, but the former will use the correct ClassLoader/ JAR, while I'm not sure with the latter) (不确定它是否有区别,但前者将使用正确的 ClassLoader/JAR,而我不确定后者)

So there are several ways to get a resource from a jar and each has slightly different syntax where the path needs to be specified differently.因此,有多种方法可以从 jar 中获取资源,每种方法的语法略有不同,需要以不同方式指定路径。

The best explanation I have seen is this article from InfoWorld .我见过的最好的解释是这篇来自InfoWorld 的文章。 I'll summarize here, but if you want to know more you should check out the article.我会在这里总结,但如果你想了解更多,你应该看看这篇文章。

Methods方法

  1. ClassLoader.getResourceAsStream() . ClassLoader.getResourceAsStream()

Format: "/"-separated names;格式:“/”-分隔的名称; no leading "/" (all names are absolute).没有前导“/”(所有名称都是绝对的)。

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

  1. Class.getResourceAsStream()

Format: "/"-separated names;格式:“/”-分隔的名称; leading "/" indicates absolute names;前导“/”表示绝对名称; all other names are relative to the class's package所有其他名称都相对于类的包

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

Updated Sep 2020: Changed article link. 2020 年 9 月更新:更改了文章链接。 Original article was from Javaworld, it is now hosted on InfoWorld (and has many more ads)原始文章来自 Javaworld,它现在托管在 InfoWorld 上(并且有更多广告)

Don't use absolute paths, make them relative to the 'resources' directory in your project.不要使用绝对路径,使它们相对于项目中的“资源”目录。 Quick and dirty code that displays the contents of MyTest.txt from the directory '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);
}

You might want to try this to get the stream ie first get the url and then open it as stream.您可能想尝试使用此方法来获取流,即首先获取 url,然后将其作为流打开。

URL url = getClass().getResource("/initialization/Lifepaths.txt"); 
InputStream strm = url.openStream(); 

I once had a similar question: Reading txt file from jar fails but reading image works我曾经有一个类似的问题: 从 jar 读取 txt 文件失败,但读取图像有效

I found myself in a similar issue.我发现自己遇到了类似的问题。 Since I am using maven I needed to update my pom.xml to include something like this:由于我使用的是 maven,因此我需要更新我的 pom.xml 以包含如下内容:

   ...
</dependencies>
<build>
    <resources>
        <resource>
            <directory>/src/main/resources</directory>
        </resource>
        <resource>
            <directory>../src/main/resources</directory>
        </resource>
    </resources>
    <pluginManagement>
        ...

Note the resource tag in there to specify where that folder is.请注意其中的资源标签以指定该文件夹的位置。 If you have nested projects (like I do) then you might want to get resources from other areas instead of just in the module you are working in. This helps reduce keeping the same file in each repo if you are using similar config data如果您有嵌套项目(就像我一样),那么您可能希望从其他区域获取资源,而不仅仅是在您正在使用的模块中。如果您使用类似的配置数据,这有助于减少在每个 repo 中保留相同的文件

There seems to be issue with the ClassLoader that you are using.您使用的 ClassLoader 似乎存在问题。 Use the contextClassLoader to load class.使用 contextClassLoader 加载类。 This is irrespective of whether it is in a static/non-static method这与是否在静态/非静态方法中无关

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

Roughly speaking:粗略地说:

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

Suppose your project structure is like the following:假设您的项目结构如下所示:

├── src
│   ├── main
│   └── test
│   └── test
│       ├── java
│       │   └── com
│       │       └── github
│       │           └── xyz
│       │               └── proj
│       │                   ├── MainTest.java
│       │                   └── TestBase.java
│       └── resources
│           └── abcd.txt
└── target
    └── test-classes
        ├── com
        └── abcd.txt

// 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

What worked for me was to add the file under My Project/Java Resources/src and then use对我有用的是在My Project/Java Resources/src下添加文件,然后使用

this.getClass().getClassLoader().getResourceAsStream("myfile.txt");

I didn't need to explicitly add this file to the path (adding it to /src does that apparently)我不需要将此文件显式添加到路径中(将它添加到/src显然是这样做的)

The default JVM classloader will use parent-classloader to load resources first:默认的 JVM 类加载器将首先使用父类加载器来加载资源: 删除门父类加载器 . .

Lifepaths.class.getClass() 's classloader is bootstrap classloader , so getResourceAsStream will search $JAVA_HOME only, regardless of user provided classpath . Lifepaths.class.getClass()的类加载器是bootstrap classloader ,所以getResourceAsStream将只搜索 $JAVA_HOME ,而不管用户提供的classpath Obviously, Lifepaths.txt is not there.显然,Lifepaths.txt 不存在。

Lifepaths.class 's classloader is system classpath classloader , so getResourceAsStream will search user-defined classpath and Lifepaths.txt is there. Lifepaths.class的类加载器是system classpath classloader ,因此getResourceAsStream将搜索用户定义的classpath而 Lifepaths.txt 就在那里。

When using java.lang.Class#getResourceAsStream(String name) , name which is not start with '/' will be added with package name as prefix.使用java.lang.Class#getResourceAsStream(String name) ,不以“/”开头的名称将添加package name作为前缀。 If you want avoid this, please using java.lang.ClassLoader#getResourceAsStream .如果您想避免这种情况,请使用java.lang.ClassLoader#getResourceAsStream For example:例如:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
String resourceName = "Lifepaths.txt";
InputStream resourceStream = loader.getResourceAsStream(resourceName); 

Don't know if of help, but in my case I had my resource in the /src/ folder and was getting this error.不知道是否有帮助,但就我而言,我的资源位于 /src/ 文件夹中,但出现此错误。 I then moved the picture to the bin folder and it fixed the issue.然后我将图片移动到 bin 文件夹并解决了问题。

Make sure your resource directory (eg "src") is in your classpath (make sure it's a source directory in your build path in eclipse).确保您的资源目录(例如“src”)在您的类路径中(确保它是 eclipse 中构建路径中的源目录)。

Make sure clazz is loaded from the main classloader.确保从主类加载器加载 clazz。

Then, to load src/initialization/Lifepaths.txt, use然后,加载 src/initialization/Lifepaths.txt,使用

clazz.getResourceAsStream("/initialization/Lifepaths.txt");

Why: clazz.getResourcesAsStream(foo) looks up foo from within the classpath of clazz , relative to the directory clazz lives in .为什么: clazz.getResourcesAsStream(foo)clazz 的类路径中查找 foo ,相对于 clazz 所在的目录 The leading "/" makes it load from the root of any directory in the classpath of clazz.前导“/”使其从 clazz 类路径中任何目录的根目录加载。

Unless you're in a container of some kind, like Tomcat, or are doing something with ClassLoaders directly, you can just treat your eclipse/command line classpath as the only classloader classpath.除非您在某种容器中,例如 Tomcat,或者直接使用 ClassLoaders 执行某些操作,否则您可以将 eclipse/命令行类路径视为唯一的类加载器类路径。

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

<packaging>jar</packaging>

What you really need is a full absolute classPath for the file.您真正需要的是文件的完整绝对类路径。 So instead of guessing it, try to find out the ROOT and then move the file to a better location base one <.war> file structures...因此,与其猜测,不如尝试找出根目录,然后将文件移动到基​​于 <.war> 文件结构的更好位置...

URL test1 = getClass().getResource("/");
URL test2 = getClass().getClassLoader().getResource("/");            
URL test3 = getClass().getClassLoader().getResource("../");

logger.info(test1.getPath()); 
logger.info(test2.getPath());
logger.info(test3.getPath());

What worked for me is I placed the file under对我有用的是我将文件放在

src/main/java/myfile.log

and

InputStream is = getClass().getClassLoader().getResourceAsStream("myfile.log");
        
        if (is == null) {
            throw new FileNotFoundException("Log file not provided");
        }

就我而言,除非我从文件名中删除空格,否则什么都行不通...

Please remove请删除

../src/main/resources ../src/main/resources

or include file you are trying to read或包含您尝试读取的文件

在 pom.xml 中管理或删除 ../src/main/resources

My caller class was in src/main/...我的调用者类在src/main/...

What helped me to load resource from src/test/resources/folder/file.properties是什么帮助我从src/test/resources/folder/file.properties加载资源

`properties.load(getClass().getClassLoader().getResourceAsStream("folder/file.properties"));`

https://howtodoinjava.com/java/io/read-file-from-resources-folder/ https://howtodoinjava.com/java/io/read-file-from-resources-folder/

Java 11爪哇 11

jdk >=9 需要在module-info模块中把非根目录/非共父目录的包给它open了。 jdk >=9 需要在module-info模块中把非根目录/非共父目录的包给它open了。

jdk >=9 need open resource dir in module-info.java , such as : jdk >=9 需要在 module-info.java 中打开资源目录,例如:

  • src源文件
    • java爪哇
    • resoureces资源
      • conf配置文件
        • config.json配置文件
      • log4j2.xml log4j2.xml
      • openapi.yaml openapi.yaml

If you need read conf/config.json , you need two step :如果你需要阅读 conf/config.json ,你需要两步:

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

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

Else if you need read other in root , it's only :否则,如果您需要在 root 中阅读 other ,它只是:

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

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

While not intended to be an answer, I'm presenting this suggestion as an answer so I can get the screenshot in.虽然不打算作为答案,但我将此建议作为答案提出,以便我可以获取屏幕截图。

For those of you developing on a Windows platform, I highly recommend the Microsoft utility ProcMon, or Process Monitor.对于那些在 Windows 平台上开发的人,我强烈推荐 Microsoft 实用程序 ProcMon,或 Process Monitor。

Process Monitor is one utility in a suite of utilities Microsoft gives away (you don't even need to be signed in to download). Process Monitor 是 Microsoft 提供的一组实用程序中的一个实用程序(您甚至不需要登录即可下载)。 They are all available at sysinternals.com, the original host that Microsoft acquired and just kept.它们都可以在 sysinternals.com 上找到,这是微软收购并保留的原始主机。

Process Monitor can monitor a ton of events that are associated with any running process. Process Monitor 可以监控与任何正在运行的进程相关的大量事件。 If you specify the File Open event and provide the file name (or part of the file name), it will log which process attempted to open the file and it will show every directory searched.如果您指定文件打开事件并提供文件名(或文件名的一部分),它将记录尝试打开文件的进程并显示每个搜索到的目录。 This can be useful when you don't know where your running code is looking for the file you specified in your source/config.当您不知道正在运行的代码在哪里寻找您在 source/config.php 中指定的文件时,这会很有用。 Here's an example:下面是一个例子:

在此处输入图片说明

Here I'm looking for (and not finding) a schema file (XSD) so that the code can use it to validate some user supplied XML.在这里,我正在寻找(而不是找到)模式文件 (XSD),以便代码可以使用它来验证某些用户提供的 XML。

If you are using IDEA, make sure to mark your resources folder as 'Resources' so that the path can be recognized by IDE correctly.如果您使用的是 IDEA,请确保将您的资源文件夹标记为“资源”,以便 IDE 可以正确识别该路径。

Let's say you have a file named 'book.json' in 'resources/', then to use the resources in it, you can do it like this假设你在'resources/'中有一个名为'book.json'的文件,那么要使用其中的资源,你可以这样做

InputStream input = Main.class.getResourceAsStream("/book.json");

在此处输入图像描述

Lifepaths.class.getClass(). Lifepaths.class.getClass()。 getResourceAsStream("Lifepaths.txt")); getResourceAsStream("Lifepaths.txt"));

I know there are different answers here.我知道这里有不同的答案。 Mine worked like this.我的工作是这样的。 Added the file in the resources directory.在资源目录中添加了文件。 And in the executable code I mentioned the path for that file with "/" as prefix within the quotes of the filename.在可执行代码中,我提到了该文件的路径,在文件名的引号内以“/”作为前缀。

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

Problem with me was that resource was not in src folder.我的问题是资源不在 src 文件夹中。

Coming late to the party.晚会迟到了。 Depending on the JDK version you are using (maybe it is time to review the StackOverflow 'question already answered'?) JPMS can impact on the resources you are able to load (or not).根据您使用的 JDK 版本(也许是时候查看 StackOverflow 的“问题已回答”?)JPMS 可能会影响您能够加载(或不能加载)的资源。

Packaging my code as module I had to do that:将我的代码打包为模块我必须这样做:

Thread.currentThread().getClass().getModule().getResourceAsStream("resourceName"); Thread.currentThread().getClass().getModule().getResourceAsStream("resourceName");

And then it worked然后它起作用了

@Emracool... I'd suggest you an alternative. @Emracool ...我建议你另一种选择。 Since you seem to be trying to load a *.txt file.由于您似乎正在尝试加载 *.txt 文件。 Better to use FileInputStream() rather then this annoying getClass().getClassLoader().getResourceAsStream() or getClass().getResourceAsStream() .最好使用FileInputStream()而不是这个烦人的getClass().getClassLoader().getResourceAsStream()getClass().getResourceAsStream() At least your code will execute properly.至少你的代码会正确执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM