Получение файла ресурса изнутри jar - PullRequest
0 голосов
/ 26 июня 2019

Мне нужно получить ресурс из корня приложения, когда он упакован в jar. Мой проект такой:

ProjectRoot
  resource.txt //want to access from here
  src
    main
       java
         package1
           package2
              package3
                 Main.java
  target
    app.jar
    classes
         resource.txt //works when here
         package1
           package2
              package3
                 Main.class

Я использую этот код:

Path path = Paths.get("resource.txt");

Когда запускается перед упаковкой в ​​банку, он находит файл просто отлично (внутри ProjectRoot). При запуске банка он не может его найти и преобразует этот путь в target/resource.txt.

Этот код:

BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
                "resource.txt")));

при запуске перед упаковкой ищет ресурс внутри target/classes. После упаковки он утверждает, что взял ресурс с .../target/app.jar!/resource.txt.

Этот код:

BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
                    "/resource.txt")));

Я не могу понять, где находится ресурс, но, похоже, он не ProjectRoot.

Все, что я хочу сделать, это разместить ресурс внутри ProjectRoot и иметь доступ к нему как из внешнего jar-файла (при запуске файлов класса из IDE), так и изнутри (после упаковки файлов в jar-файл с помощью Maven ).

РЕДАКТИРОВАТЬ : НУЖЕН КОД, ЧТОБЫ РАБОТАТЬ ОБА ДЛЯ ПРЕДВАРИТЕЛЬНОЙ И ПОЧТОВОЙ упаковки. ЗНАЧЕНИЕ: Если я запускаю Main.java ИЗ INSIDE IDE, ЭТО БУДЕТ ПОЛУЧИТЬ РЕСУРС; Если я положу все в банку и запустите банку, он получит ресурс - все с тем же кодом.

Ответы [ 2 ]

1 голос
/ 27 июня 2019

Maven использует то, что называется Стандартное расположение каталогов .Если вы не придерживаетесь этого макета, то плагины не могут выполнять свою работу правильно.Технически вы можете настроить Maven для использования разных каталогов, но в 99,999% случаев это не нужно.

Одна из особенностей этого макета заключается в том, что рабочие файлы входят в:

  • <project-dir>/src/main/java
    • Все *.java файлы
  • <project-dir>/src/main/resources
    • Все не *.java файлы (которые предназначены для ресурсов)

При создании проекта исходные файлы Java компилируются, а файлы *.class помещаются в каталог target/classes;это сделано maven-compiler-plugin.Тем временем файлы ресурсов копируются из src/main/resources в target/classes;за это отвечает maven-resources-plugin.

Примечание: См. Введение в жизненный цикл сборки для получения дополнительной информации о фазах и о том, какие подключаемые модули выполняются какимифаза.Этот вопрос переполнения стека также может быть полезен.

При запуске приложения из IDE (возможно, через exec-maven-plugin) помещается каталог target/classesв classpath. Это означает, что все скомпилированные классы из src/main/java и все скопированные ресурсы из src/main/resources доступны для использования через classpath.

Затем, когда вы упаковываете свое приложение в JARфайл, все файлы в target/classes добавляются в получившийся файл JAR (обрабатывается maven-jar-plugin). Сюда входят ресурсы, скопированные с src/main/resources.Когда вы запускаете приложение, используя этот JAR-файл, ресурсы все еще доступны для использования через classpath, потому что они встроены в JAR-файл.

Чтобы сделать resource.txt доступным в classpath, просто переместите:

<project-dir>/resource.txt

Кому:

<project-dir>/src/main/resources/resource.txt.

Тогда вы можете использовать Class#getResource с /resource.txt в качестве пути, и все должно сработать для вас.URL, возвращаемый getResource, будет отличаться в зависимости от того, выполняете ли вы против target/classes или против файла JAR.

При выполнении против target/classes вы получите что-то вроде:

file:///.../<project-dir>/target/classes/resource.txt

При выполнении с файлом JAR вы получите что-то вроде:

jar:file:///.../<project-dir>/target/projectname-version.jar!/resource.txt

Примечание: Все это предполагает, что resource.txt фактически должнобыть ресурсом, а не внешним файлом.Ресурсы обычно доступны только для чтения после развертывания в файле JAR;если вам нужен доступный для записи файл, то вы можете использовать назначенное место для файла (например, папку в домашнем каталоге пользователя).Обычно доступ к внешним файлам осуществляется с помощью java.io.File или java.nio.file.*.Помните, что ресурсы - это не то же самое, что обычные файлы.

Теперь, если бы вы поместили resource.txt прямо под <project-dir>, это бы ничего не значило для Maven .Он не будет скопирован в target/classes или не окажется в файле JAR, что означает, что ресурс никогда не будет доступен в classpath.Итак, просто для повторения, все ресурсы идут под src/main/resources.


Проверьте Javadoc java.lang.Class#getResource(String) для получения дополнительной информации о пути, напримеркак, когда использовать ведущий /, а когда нет.Ссылка указывает на Javadoc для Java 12, который включает информацию о ресурсах и модулях (модули JPMS / Jigsaw, а не модули Maven);если вы не используете модули, вы можете игнорировать эту часть документации.

1 голос
/ 26 июня 2019

Использование: Main.class.getResource("/resource.txt").

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

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

TL; DR: Из форм SomeClass.class.getClassLoader().getResource, getClass().getResource и MyClass.class.getResource только последняя является правильной, остальные строго уступают и поэтому не должны использоваться ввсе.

...