Nano Hash - криптовалюты, майнинг, программирование

Получение файла ресурсов из банки

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

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). При запуске jar он не может его найти и преобразует этот путь в 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 и получить к нему доступ как из внешней банки (при запуске файлов классов из IDE), так и изнутри (после упаковки файлов в файл jar с помощью Maven).

РЕДАКТИРОВАТЬ: МНЕ НУЖЕН КОД, ЧТОБЫ РАБОТАТЬ КАК ДЛЯ ДО, И ПОСЛЕ-упаковки. ЗНАЧЕНИЕ: Если я запускаю Main.java ИЗНУТРИ IDE, ОН ПОЛУЧИТ РЕСУРС; ЕСЛИ Я УПАКУЮ ВСЕ В JAR И ЗАПУСКУ JAR, ЭТО ПОЛУЧИТ РЕСУРС - ВСЕ С ОДНИМ КОДОМ.

26.06.2019

  • В Maven ресурсы идут под src/main/resources. В противном случае они не копируются в выходной каталог или не встраиваются в файл JAR и, таким образом, не попадают в путь к классам во время выполнения. 26.06.2019
  • @Слав, я так и начал. Я не нашел способа исправить код, который мог бы получить доступ к этой папке до и после упаковки. 26.06.2019
  • Если он находится непосредственно под src/main/resources, то getResource("/resource.txt") должен работать. 26.06.2019
  • @Slaw какой полный код? Main.class.getResource("/resource.txt")? 26.06.2019
  • Это должно сработать. Обратите внимание, что начальный / делает его абсолютным путем, тогда как начальный / не делает его относительным к местоположению Class, для которого вы вызываете getResource. И помните, ресурсы ищутся в пути к классам. 26.06.2019
  • @Slaw нет, он смотрит внутрь ProjectRoot/target/classes 26.06.2019
  • Да, потому что, когда Maven выполняет код для target/classes, это корень пути к классам. После того, как вы упакуете приложение в файл JAR и выполните его для указанного файла JAR, оно будет искать ресурс в файле JAR. Вот почему этот API использует путь к классам... это независимый от кода способ получения ресурсов. 26.06.2019
  • @Slaw, как мне получить ресурс изнутри ProjectRoot или хотя бы ProjecRoot/src/main/resources, если он смотрит только на ProjectRoot/target/classes? 27.06.2019
  • Файлы в src/main/resources копируются в target/classes на одном из этапов Maven. При упаковке в JAR все файлы в target/classes добавляются в JAR. 27.06.2019
  • Ваше редактирование не меняет ничего из того, что я говорил. 27.06.2019

Ответы:


1

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

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

  • <project-dir>/src/main/java
    • All *.java files
  • <project-dir>/src/main/resources
    • All non-*.java files (that are meant to be resources)

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

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

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

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

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

<project-dir>/resource.txt

To:

<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, что означает, что ресурс никогда не будет доступен в пути к классам. Итак, повторюсь: все ресурсы относятся к категории src/main/resources.


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

26.06.2019
  • Заработало, спасибо. Для будущих читателей: в конце концов я использовал этот код для открытия файлов, расположенных в src/main/resources:` BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream("/resource.txt")));. После запуска команды package Maven все, что находится внутри src/main/resources, копируется внутрь target/classes. Вот откуда Main.java из IDE берет файл. В то же время команда package создает банку, которая берет файлы из target/classes и помещает их в свой корень. 02.07.2019

  • 2

    Используйте 1_.

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

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

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

    26.06.2019
  • Main.class.getResource("/resource.txt") смотрит внутрь ProjectRoot/target/app.jar!/resource.txt, а не только ProjectRoot. 26.06.2019
  • @parsecer Вот что должно произойти, если resource.txt на самом деле должен быть ресурсом. 26.06.2019
  • Конечно, это это корень. Точно так же, как Main.class копируется в этот jar-файл, этот ресурс является такой же частью вашего приложения, как и этот файл класса, и он должен находиться внутри jar-файла. И тогда Main.class.getResource(/resource.txt) найдет его для вас. 27.06.2019
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..