Вопрос-ответ

getResourceAsStream returns null

getResourceAsStream возвращает null

Я загружаю текстовый файл из пакета в скомпилированный JAR моего Java-проекта. Соответствующая структура каталогов выглядит следующим образом:

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

Ни то, ни другое не работает. До сих пор я читал многочисленные вопросы по этой теме, но ни один из них не был полезным - обычно они просто говорят загружать файлы, используя корневой путь, что я уже делаю. Это, или просто загрузите файл из текущего каталога (just load filename), что я тоже пробовал. Файл компилируется в JAR в соответствующем месте с соответствующим именем.

Как мне это решить?

Переведено автоматически
Ответ 1

Lifepaths.class.getClass().getResourceAsStream(...) загружает ресурсы с помощью загрузчика системного класса, очевидно, происходит сбой, потому что он не видит ваши JARS

Lifepaths.class.getResourceAsStream(...) загружает ресурсы с помощью того же загрузчика классов, который загружал класс Lifepaths, и у него должен быть доступ к ресурсам в ваших JARS

При вызове getResourceAsStream (name) имя должно начинаться с "/". Я не уверен, необходимо ли это, но у меня и без этого проблема

Ответ 2

Правила следующие:


  1. проверьте расположение файла, который вы хотите загрузить внутри JAR (и, таким образом, также убедитесь, что он действительно добавлен в JAR)

  2. используйте либо абсолютный путь: путь начинается в корне JAR

  3. используйте относительный путь: путь начинается с каталога пакета вызываемого вами класса getResource / getResoucreAsStream

И попробуйте:

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

вместо

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

(не уверен, имеет ли это значение, но в первом случае будет использоваться правильный ClassLoader / JAR, в то время как со вторым я не уверен)

Ответ 3

Итак, есть несколько способов получить ресурс из jar, и каждый из них имеет немного другой синтаксис, где путь должен быть указан по-разному.

Лучшее объяснение, которое я видел, - это статья из InfoWorld. Здесь я подведу итог, но если вы хотите узнать больше, вам следует ознакомиться со статьей.

Методы


  1. ClassLoader.getResourceAsStream().

Формат: имена, разделенные буквами "/"; без начальных "/" (все имена являются абсолютными).

Пример: this.getClass().getClassLoader().getResourceAsStream("some/pkg/resource.properties");


  1. Class.getResourceAsStream()

Формат: "/" - имена, разделенные буквами; начало "/" указывает абсолютные имена; все остальные имена относятся к пакету класса

Пример: this.getClass().getResourceAsStream("/some/pkg/resource.properties");

Обновлено в сентябре 2020 года: изменена ссылка на статью. Оригинальная статья была с Javaworld, теперь она размещена на InfoWorld (и содержит еще много рекламы)

Ответ 4

Грубо говоря:

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

java