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

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

/src/initialization/Lifepaths.txt

Код для загрузки файла:

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"

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

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

Ответ 1

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

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

Ответ 2

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

  • проверьте местоположение файла, который вы хотите загрузить внутри JAR (и, следовательно, также убедитесь, что он фактически добавлен в JAR)
  • используйте либо абсолютный путь: путь начинается в корневом каталоге JAR
  • использовать относительный путь: путь начинается в каталоге пакета класса, который вы вызываете getResource/getResoucreAsStream

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

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

вместо

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

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

Ответ 3

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

Лучшее объяснение, которое я видел, - это статья из JavaWorld. Я опишу здесь, но если вы хотите узнать больше, вы должны проверить статью.

Методы

1) ClassLoader.getResourceAsStream().

Формат: "/" - разделенные имена; нет ведущего "/" (все имена являются абсолютными).

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

2) Class.getResourceAsStream()

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

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

Ответ 4

Не используйте абсолютные пути, сделайте их относительно каталога ресурсов в вашем проекте. Быстрый и грязный код, отображающий содержимое 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);
}

Ответ 5

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

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

У меня был аналогичный вопрос: Чтение txt файла из jar не выполняется, но чтение изображений работает

Ответ 6

Кажется, что проблема с ClassLoader, который вы используете. Используйте contextClassLoader для загрузки класса. Это независимо от того, находится ли он в статическом/нестационарном методе

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

Ответ 7

Я оказался в подобной проблеме. Поскольку я использую maven, мне нужно было обновить pom.xml, чтобы включить что-то вроде этого:

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

Обратите внимание на тег ресурса, чтобы указать, где находится эта папка. Если у вас есть вложенные проекты (например, я), вы можете захотеть получить ресурсы из других областей, а не только в том модуле, в котором работаете. Это помогает уменьшить сохранение одного и того же файла в каждом репо, если вы используете похожие данные конфигурации

Ответ 8

Не знаю, нужна ли помощь, но в моем случае у меня был свой ресурс в папке/src/и я получал эту ошибку. Затем я переместил изображение в папку bin и исправил проблему.

Ответ 9

Убедитесь, что ваш каталог ресурсов (например, "src" ) находится в вашем пути к классу (убедитесь, что он является исходным каталогом в пути сборки в eclipse).

Убедитесь, что clazz загружен из основного загрузчика классов.

Затем, чтобы загрузить src/initialization/Lifepaths.txt, используйте

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

Почему: clazz.getResourcesAsStream(foo) ищет foo из класса class clazz по сравнению с классом clazz, в котором живет. Ведущий "/" заставляет его загружать из корня любой директории в classpath clazz.

Если вы не находитесь в контейнере какого-то типа, например Tomcat, или делаете что-то с ClassLoaders напрямую, вы можете просто рассматривать свой путь класса eclipse/командной строки как единственный путь класса classloader.

Ответ 10

Что сработало для меня, так это добавить файл в My Project/Java Resources/src, а затем использовать

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

Мне не нужно было объяснять добавление этого файла в путь (добавление его в /src делает это, по-видимому)

Ответ 11

В моем случае ничего не получалось, если я не удалил пробелы из имен файлов...

Ответ 12

Загрузчик классов JVM по умолчанию будет сначала использовать родительский загрузчик классов: deletegate-parent-classloader.

Lifepaths.class.getClass() классов 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); 

Ответ 13

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

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

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

Ответ 14

если вы используете Maven, убедитесь, что ваша упаковка - "баночка", а не "пом".

<packaging>jar</packaging>

Ответ 15

@Emracool... Я бы предложил вам альтернативу. Так как вы пытаетесь загрузить файл *.txt. Лучше использовать FileInputStream(), а не это раздражающее getClass().getClassLoader().getResourceAsStream() или getClass().getResourceAsStream(). По крайней мере, ваш код будет выполнен правильно.