Метод getResource не может найти ресурс

Внутри упакованного файла JAR у меня есть текстовый документ, расположенный в каталоге списка. Итак, внутри файла JAR есть каталог списка и текстовый документ под названием «Страны».

Я просто вызывал class.getResource("/list/Countries.txt"). Очень просто. Это должно сработать. Но этого не произошло. Затем я попробовал без косой черты в начале строки, все равно не получилось. Я попробовал все комбинации class.getResource и class.getClassLoader.getResource. Проблема все та же.

Кстати. По тому же пути находится каталог под названием «сцена», а внутри него находится файл FXML. Другой класс легко читает файл FXML и загружает его. Но когда дело доходит до этого текстового документа, все совсем по-другому. Сцена/и список/каталоги находятся на одном уровне, я могу вызвать class.getResource("/scene/example-scene.fxml") и не столкнусь с какой-либо проблемой. Очень интересно!

public List<String> getCountries() {
    InputStream resourceAsStream = TextFileRepository.class.getResourceAsStream( "/list/Countries.txt");

    try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceAsStream))) {
        return reader.lines().toList();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

Вы уверены, что файл находится в файле Jar и в правильном месте? Можете ли вы перечислить нам его содержимое? jar tf *filename*

markspace 01.09.2024 02:34

InputStream resourcesAsStream = TextFileRepository.class.getResourceAsStream( "/list/Countries.txt"); потребуется, чтобы запись list находилась в корне вашей банки

g00se 01.09.2024 11:33
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы почти все делаете правильно. Это MyClass.class.getResourceAsStream; вы правильно поняли эту часть. Однако сам вызов getResource должен быть X в try (X); затем вы можете выбрать, какой бы стиль вы ни предпочли, разместить создание буферного чтения и входного потока отдельно в блоке try-with или просто переместить это в сам try, потому что они не представляют ресурсы, которые вы должны закрыть:

try (var raw = TextFileRepository.class.getResourceAsStream("/list/Countries.txt")) {
  return new BufferedReader(new InputStreamReader(raw))
    .lines().toList();
}

Аргумент анализируется как «относительно корня jar-файла, в котором находится MyClass», если он начинается с косой черты, и анализируется как «относительно каталога в jar-файле, в котором находится MyClass.class», если это не так. В вашем примере он начинается с косой черты, поэтому в банке он ищет list/Countries.txt - на верхнем уровне и именно с этим регистром.

Единственный возможный вывод заключается в том, что этот файл на самом деле не находится в вашей банке.

Несколько инструментов и советов, которые вы можете использовать, чтобы проанализировать, что происходит не так; вы должны найти проблему, если выполните следующие действия:

  • Содержимое jar чувствительно к регистру, даже если ваша ОС не чувствительна. Возможно, в вашей баночке вместо /list/countries.txt находится /list/Countries.txt?

  • Возьмите любой класс верхнего уровня (например, не класс, вложенный в другой класс), скажем, класс с именем MyClass.class, тогда вы всегда можете написать: MyClass.class.getResource("MyClass.class") для любого класса. Распечатайте это. Он напечатает что-то вроде:

jar:file:/home/eray/project/myproj/myproj.jar!/com/foo/pkg/MyClass.class

Теперь вы точно знаете, какой jar-файл на самом деле просматривается. Возможно, у вас есть несколько файлов jar, и вы проверяете наличие /list/countries.txt не в том файле.

Как только вы это сделаете, запустите командную строку и выполните:

# Lists all entries in the jar file
jar tvf /home/eray/project/myproj/myproj.jar

чтобы проверить и быть уверенным на 100%, запустите:

# Extracts specifically /list/countries.txt
jar xvf /home/eray/project/myproj/myproj.jar /list/countries.txt

Но используйте копирование/вставку как для имени файла jar, так и для текста записи jar! - вы копируете/вставляете имя файла jar, захватывая элемент между file: и ! в выводе печати TextFileRepository.class.getResource("TextFileRepository.class"), и копируете/вставляете запись прямо из своего кода - из материала в строковых кавычках, который вы передаете в качестве аргумента getResourceAsStream.

Затем вы проверяете, не печатает ли команда ничего (в этом случае мы обнаружили проблему — этой записи нет в этом банке) или печатает «inflated: list/countries.txt», и в этом случае это так, и происходит что-то еще. Это будет точно воспроизведено - например, если вы испортите регистр, эта команда jar не извлечет ни одного файла.

С аргументами jar и тем, как они справляются с точками и косыми чертами, происходят некоторые странные вещи. Например, jar не работает (как ни странно, до сих пор) при попытке извлечь файл с именем FOO2.0; аналогичная ерунда с точками и тире есть и в getResourceAsStream. Однако имя вашего файла совсем не странное. Оно не состоит из множества точек в имени файла (только из одной, и это нормально).

(С помощью копирования мы также исключаем, что любые символы в имени записи файла jar или в исходном файле выглядят похожими или идентичными, но представляют собой разные символы Юникода. Например, аа — это два одинаковых символа, верно? Нет — они выглядят одинаково, но не являются одним и тем же символом. Вторая буква «а» — простая «а», первая «а» Строчная кириллическая буква А). Вот почему так важно копировать/вставлять; это в основном устраняет «путаницу с Юникодом» как причину.

Я обнаружил проблему, и это произошло потому, что строковая переменная, представляющая путь к ресурсу, каким-то образом вернула значение null из-за примененного мной сложного шаблона. Я предполагал, что устраняю проблему, связанную с переменной, напрямую указывая путь, но из-за этого сложного шаблона снова возникло другое исключение. Здесь я узнал, что мне следует отлаживать код и тестировать его как можно раньше. Я не должен переходить к дальнейшим реализациям, не протестировав текущую реализацию.

Eray 01.09.2024 20:33

Другие вопросы по теме