Вопрос-ответ

How to get a path to a resource in a Java JAR file

Как получить путь к ресурсу в файле Java JAR

Я пытаюсь получить путь к ресурсу, но мне не повезло.

Это работает (как в IDE, так и с JAR), но таким образом я не могу получить путь к файлу, только содержимое файла:

ClassLoader classLoader = getClass().getClassLoader();
PrintInputStream(classLoader.getResourceAsStream("config/netclient.p"));

Если я сделаю это:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("config/netclient.p").getFile());

Результатом является:
java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

Есть ли способ получить путь к файлу ресурсов?

Переведено автоматически
Ответ 1

Это сделано намеренно. Содержимое "файла" может быть недоступно в виде файла. Помните, что вы имеете дело с классами и ресурсами, которые могут быть частью файла JAR или другого вида ресурсов. Загрузчику классов не обязательно предоставлять дескриптор файла для ресурса, например, файл jar, возможно, не был расширен на отдельные файлы в файловой системе.

Все, что вы можете сделать, получив файл a java.io.Это можно сделать, скопировав поток во временный файл и проделав то же самое, если файл a java.io.абсолютно необходим.

Ответ 2

При загрузке ресурса убедитесь, что вы заметили разницу между:

getClass().getClassLoader().getResource("com/myorg/foo.jpg") //relative path

и

getClass().getResource("/com/myorg/foo.jpg")); //note the slash at the beginning

Я думаю, эта путаница вызывает большинство проблем при загрузке ресурса.


Кроме того, когда вы загружаете изображение, его проще использоватьgetResourceAsStream():

BufferedImage image = ImageIO.read(getClass().getResourceAsStream("/com/myorg/foo.jpg"));

Когда вам действительно нужно загрузить файл (не изображение) из архива JAR, вы можете попробовать следующее:

File file = null;
String resource = "/com/myorg/foo.xml";
URL res = getClass().getResource(resource);
if (res.getProtocol().equals("jar")) {
try {
InputStream input = getClass().getResourceAsStream(resource);
file = File.createTempFile("tempfile", ".tmp");
OutputStream out = new FileOutputStream(file);
int read;
byte[] bytes = new byte[1024];

while ((read = input.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.close();
file.deleteOnExit();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
} else {
//this will probably work in your IDE, but not from a JAR
file = new File(res.getFile());
}

if (file != null && !file.exists()) {
throw new RuntimeException("Error: File " + file + " not found!");
}
Ответ 3

Ответ в одну строку таков -

String path = this.getClass().getClassLoader().getResource(<resourceFileName>).toExternalForm()

В основном getResource метод выдает URL-адрес. Из этого URL-адреса вы можете извлечь путь, вызвав toExternalForm().

Ответ 4

Я некоторое время возился с этой проблемой, потому что, как ни странно, ни одно решение, которое я нашел, на самом деле не сработало! Рабочий каталог часто не является каталогом JAR, особенно если JAR (или любая программа, если на то пошло) запускается из меню "Пуск" в Windows. Итак, вот что я сделал, и это работает для файлов .class, запускаемых извне JAR так же хорошо, как и для JAR. (Я тестировал это только под Windows 7.)

try {
//Attempt to get the path of the actual JAR file, because the working directory is frequently not where the file is.
//Example: file:/D:/all/Java/TitanWaterworks/TitanWaterworks-en.jar!/TitanWaterworks.class
//Another example: /D:/all/Java/TitanWaterworks/TitanWaterworks.class
PROGRAM_DIRECTORY = getClass().getClassLoader().getResource("TitanWaterworks.class").getPath(); // Gets the path of the class or jar.

//Find the last ! and cut it off at that location. If this isn't being run from a jar, there is no !, so it'll cause an exception, which is fine.
try {
PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('!'));
} catch (Exception e) { }

//Find the last / and cut it off at that location.
PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('/') + 1);
//If it starts with /, cut it off.
if (PROGRAM_DIRECTORY.startsWith("/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(1, PROGRAM_DIRECTORY.length());
//If it starts with file:/, cut that off, too.
if (PROGRAM_DIRECTORY.startsWith("file:/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(6, PROGRAM_DIRECTORY.length());
} catch (Exception e) {
PROGRAM_DIRECTORY = ""; //Current working directory instead.
}
java