Как указать Java правильный путь к файлу в JAR-файле? - PullRequest
1 голос
/ 31 мая 2019

Я поместил весь свой код JavaFX в исполняемый JAR-файл. Все внутри.

Когда я компилирую его с Eclipse IDE, он работает, но когда я пытаюсь выполнить JAR-файл, я получаю сообщение об ошибке.

Caused by: javafx.fxml.LoadException: 
file:/home/asus/program/JUSBPlotter/JUSBPlotter-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/se/danielmartensson/fxml/front.fxml

Когда у меня есть этот код Java

 Parent root = FXMLLoader.load(getClass().getResource("/se/danielmartensson/fxml/front.fxml"));

В файле FXML нет ничего плохого.

fx:controller="se.danielmartensson.controller.Front"

Также я получаю ошибки при попытке отобразить изображение в JavaFX.

Caused by: java.io.FileNotFoundException: file:/home/asus/program/JUSBPlotter/JUSBPlotter-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/se/danielmartensson/pictures/computer.png (No such file or directory)

Когда у меня есть этот код Java:

FileInputStream picture1 = new FileInputStream(getClass().getResource("/se/danielmartensson/pictures/computer.png").getFile());

Вопрос: Как я могу указать Java правильный путь к файлу в JAR-файле?

1 Ответ

2 голосов
/ 31 мая 2019

Следует помнить, что ресурсы - это не то же самое, что файлы, несмотря на то, что они выглядят довольно схожими, особенно перед упаковкой приложения.После упаковки приложения эти файлы ресурсов становятся записями в JAR-файле, к которым, хотя их можно рассматривать как файлы, нельзя получить такой же доступ, как и к файлам.В частности, API java.io.File не понимает, как читать эти записи.Однако вы можете получить доступ к этим записям через URL, возвращаемое Class#getResource(String) или InputStream, возвращаемое Class#getResourceAsStream(String).Обратите внимание, что последний в основном просто находит URL и, если он существует, вызывает URL#openStream().Причина, по которой вы можете получить доступ к записям JAR (т. Е. К ресурсам) с помощью URL, связана с JarURLConnection и связанными классами;Я не буду вдаваться в подробности о том, как URL обрабатываются Java, поскольку это выходит за рамки этого ответа.

Теперь, так как вы пытаетесь отобразить изображение в JavaFX, я предполагаю, что вы используете Image класс.Есть в основном три способа сообщить Image, где находится ресурс изображения.

  1. Использовать Image#<init>(String), где в аргументе URL отсутствует схема.В этом случае класс будет обрабатывать URL как путь относительно корня пути к классу и пытаться получить к нему доступ соответствующим образом.По сути, аргумент - это тот же аргумент, который вы бы указали Class#getResource(String), за исключением того, что путь должен быть абсолютным (т. Е. Не относиться ни к какому классу).Это поведение задокументировано классом Image:

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

    Примечание. Если вы используете модули, то Инкапсуляция ресурсов вступает в игру при использовании этой опции.См. GitHub Issue # 441 .

  2. Используйте тот же конструктор, что и выше, но передайте действительный URL (т. Е. У него есть схема).При использовании ресурса вы можете просто преобразовать URL, возвращаемый Class#getResource(Sring) в String, используя URL#toExternalForm().

    Image image = new Image(getClass().getResource(...).toExternalForm());
    

    Примечание: вы можететакже используйте URL#toString(), который возвращает то же значение.

  3. Используйте Image#<init>(InputStream).Здесь вы можете использовать Class#getResourceAsStream(String).Не забудьте закрыть InputStream, когда закончите с ним.

    try (InputStream is = getClass().getResourceAsStream(...)) {
        Image image = new Image(is);
    }
    

Все это предполагает, что ресурсы были правильно упакованы в ваш файл JAR при его создании.Если это не так, сначала следуйте советам, данным Хосе Переда в комментариях к вопросу.


Обратите внимание, что можно получить доступ к записям файла ZIP / JAR с помощью API java.util.zip.*java.util.jar.* API или Java NIO ZipFileSystemProvider.Каждый из них, особенно последний вариант, позволяет получить доступ к записям файла ZIP / JAR, аналогичным фактическим файлам, поскольку они специально предназначены для этого.Однако при использовании ресурсов в приложении вы должны придерживаться Class#getResource(String) и связанных с ним методов.

...