228

我正在从我的 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/initialization/Lifepaths.txt"
  • "initialization/Lifepaths.txt"
  • "Lifepaths.txt"

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

我该如何解决这个问题?

4

22 回答 22

208

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

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

于 2013-05-15T17:06:24.487 回答
68

规则如下:

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

并尝试:

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

代替

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

(不确定是否有区别,但前者将使用正确的 ClassLoader/JAR,而我不确定后者)

于 2013-05-15T16:50:50.613 回答
55

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

我见过的最好的解释是来自InfoWorld的这篇文章。我将在这里进行总结,但是如果您想了解更多信息,则应查看该文章。

方法

  1. ClassLoader.getResourceAsStream().

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

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

  1. Class.getResourceAsStream()

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

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

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

于 2013-05-15T17:12:36.697 回答
15

不要使用绝对路径,使它们相对于项目中的“资源”目录。快速而肮脏的代码,显示目录“资源”中的 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);
}
于 2014-07-16T15:58:24.830 回答
9

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

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

我曾经有一个类似的问题:Reading txt file from jar failed but reading image works

于 2013-05-26T20:55:49.507 回答
9

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

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

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

于 2016-11-08T00:12:31.177 回答
8

大致说来:

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

假设你的项目结构如下:

├── src
│   ├── main
│   └── test
│       ├── java
│       │   └── com
│       │       └── github
│       │           └── xyz
│       │               └── proj
│       │                   ├── MainTest.java
│       │                   └── TestBase.java
│       └── resources
│           └── abcd.txt
└── target
    └── test-classes  <-- this.getClass.getResource("/")
        │              `--Thread.currentThread().getContextClassLoader().getResources(".")
        ├── com
        │   └── github
        │       └── xyz
        │           └── proj  <-- this.getClass.getResource(".")
        │               ├── MainTest.class
        │               └── TestBase.class
        └── resources
            └── abcd.txt

// in MainTest.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

于 2019-09-21T16:00:31.320 回答
8

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

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

于 2015-09-27T01:56:03.373 回答
3

默认的 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 name为前缀。如果您想避免这种情况,请使用java.lang.ClassLoader#getResourceAsStream. 例如:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
String resourceName = "Lifepaths.txt";
InputStream resourceStream = loader.getResourceAsStream(resourceName); 
于 2019-07-09T09:37:04.690 回答
3

对我有用的是在下面添加文件My Project/Java Resources/src然后使用

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

我不需要显式将此文件添加到路径中(/src显然添加它)

于 2015-12-16T22:43:20.910 回答
2

不知道是否有帮助,但在我的情况下,我的资源位于 /src/ 文件夹中并且出现此错误。然后我将图片移动到 bin 文件夹并解决了问题。

于 2015-01-05T18:53:07.047 回答
2

确保您的资源目录(例如“src”)在您的类路径中(确保它是 Eclipse 中构建路径中的源目录)。

确保从主类加载器加载 clazz。

然后,要加载 src/initialization/Lifepaths.txt,请使用

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

为什么: 从clazz 的类路径中clazz.getResourcesAsStream(foo)查找 foo ,相对于 clazz 所在的目录。前导的“/”使它从 clazz 的类路径中任何目录的根目录加载。

除非您在某种容器中,例如 Tomcat,或者直接使用 ClassLoaders,否则您可以将 eclipse/命令行类路径视为唯一的类加载器类路径。

于 2015-07-21T01:33:08.813 回答
2

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

<packaging>jar</packaging>
于 2019-10-01T10:00:27.690 回答
2

您真正需要的是文件的完整绝对类路径。因此,与其猜测,不如尝试找出根目录,然后将文件移动到基​​于 <.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());
于 2020-05-25T00:47:10.853 回答
1

对我有用的是我将文件放在

src/main/java/myfile.log

InputStream is = getClass().getClassLoader().getResourceAsStream("myfile.log");
        
        if (is == null) {
            throw new FileNotFoundException("Log file not provided");
        }
于 2020-06-27T03:12:00.383 回答
0

虽然不打算作为答案,但我将此建议作为答案提出,以便我可以获取屏幕截图。

对于那些在 Windows 平台上开发的人,我强烈推荐 Microsoft 实用程序 ProcMon 或 Process Monitor。

Process Monitor 是 Microsoft 提供的一套实用程序中的一个实用程序(您甚至无需登录即可下载)。它们都可以在 sysinternals.com 上找到,这是 Microsoft 收购并保留的原始主机。

Process Monitor 可以监视与任何正在运行的进程相关的大量事件。如果您指定文件打开事件并提供文件名(或文件名的一部分),它将记录哪个进程试图打开文件并显示搜索到的每个目录。当您不知道正在运行的代码在哪里寻找您在 source/config.xml 中指定的文件时,这会很有用。这是一个例子:

在此处输入图像描述

在这里,我正在寻找(而不是找到)模式文件 (XSD),以便代码可以使用它来验证某些用户提供的 XML。

于 2021-12-29T23:40:54.683 回答
0

请删除

../src/main/资源

或包含您尝试阅读的文件

于 2021-02-22T10:07:15.853 回答
0

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

于 2021-02-22T10:09:35.410 回答
0

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

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

  • 源代码
    • 爪哇
    • 资源
      • 会议
        • 配置文件
      • 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");

否则,如果您需要在 root 中阅读其他内容,则只需:

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

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

于 2021-11-24T18:52:57.863 回答
0

我的来电者班级在src/main/...

是什么帮助我从src/test/resources/folder/file.properties

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

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

爪哇 11

于 2021-05-26T13:55:37.610 回答
0

如果您使用的是 IDEA,请确保将您的资源文件夹标记为“资源”,以便 IDE 可以正确识别路径。

假设你在'resources/'中有一个名为'book.json'的文件,那么要使用其中的资源,你可以这样做

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

在此处输入图像描述

于 2022-02-10T07:30:01.280 回答
-12

@Emracool ...我建议您选择一个替代方案。由于您似乎正在尝试加载 *.txt 文件。最好使用FileInputStream()而不是这个烦人的getClass().getClassLoader().getResourceAsStream()or getClass().getResourceAsStream()。至少您的代码将正确执行。

于 2014-04-23T09:19:51.193 回答