Внутри упакованного файла 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);
}
}
InputStream resourcesAsStream = TextFileRepository.class.getResourceAsStream( "/list/Countries.txt"); потребуется, чтобы запись list
находилась в корне вашей банки
Вы почти все делаете правильно. Это 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 из-за примененного мной сложного шаблона. Я предполагал, что устраняю проблему, связанную с переменной, напрямую указывая путь, но из-за этого сложного шаблона снова возникло другое исключение. Здесь я узнал, что мне следует отлаживать код и тестировать его как можно раньше. Я не должен переходить к дальнейшим реализациям, не протестировав текущую реализацию.
Вы уверены, что файл находится в файле Jar и в правильном месте? Можете ли вы перечислить нам его содержимое?
jar tf *filename*