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

How to read a file from jar in Java?

Как прочитать файл из jar в Java?

Я хочу прочитать XML-файл, который находится внутри одного из jar файлов, включенных в мой путь к классу. Как я могу прочитать любой файл, который включен в jar?

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

Если вы хотите прочитать этот файл из своего приложения, используйте:

InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");

Путь начинается с "/", но это путь не в вашей файловой системе, а в вашем classpath . Итак, если ваш файл находится по пути к классу "org.xml" и вызывается myxml.xml ваш путь выглядит как "/org/xml/myxml.xml".

InputStream считывает содержимое вашего файла. Вы можете перенести его в программу чтения, если хотите.

Ответ 2

Ах, это одна из моих любимых тем. По сути, есть два способа загрузить ресурс через classpath:

Class.getResourceAsStream(resource)

и

ClassLoader.getResourceAsStream(resource)

(существуют и другие способы, которые предполагают получение URL-адреса ресурса аналогичным образом, а затем открытие соединения с ним, но это два прямых способа).

Первый метод фактически делегирует второму, после искажения имени ресурса. По сути, существует два вида имен ресурсов: абсолютные (например, "/путь / к /ресурсу /resource") и относительные (например, "ресурс"). Абсолютные пути начинаются с "/".

Вот пример, который должен проиллюстрировать. Рассмотрим класс com.example.A. Рассмотрим два ресурса, один из которых расположен в /com/example/nested, другой в /top , в classpath. Следующая программа показывает девять возможных способов доступа к двум ресурсам:

пакет com.пример;

открытый класс A {

public static void main(String args[]) {

// Class.getResourceAsStream
Ресурс объекта = A.class.getResourceAsStream("вложенный");
System.out.println("1: A.class вложенный=" + ресурс);

ресурс = A.class.getResourceAsStream("/com/пример/вложенный");
System.out.println("2: A.class /com/пример/вложенный=" + ресурс);

ресурс = A.class.getResourceAsStream("top");
System.out.println("3: A.class top=" + ресурс);

ресурс = A.class.getResourceAsStream("/top");
System.out.println("4: A.class /top=" + ресурс);

// ClassLoader.getResourceAsStream
ClassLoader cl = A.class.getClassLoader();
resource = cl.getResourceAsStream("вложенный");
System.out.println("5: cl вложенный=" + resource);

resource = cl.getResourceAsStream("/com/пример/вложенный");
System.out.println("6: cl /com/пример/вложенный=" + resource);
resource = cl.getResourceAsStream("com/пример/вложенный");
System.out.println("7: cl com/пример/вложенный=" + resource);

resource = cl.getResourceAsStream("top");
System.out.println("8: cl top=" + resource);

resource = cl.getResourceAsStream("/top");
System.out.println("9: cl /top=" + resource);
}

}

Вывод программы выглядит следующим образом:

1: A.class nested=java.io.BufferedInputStream@19821f
2: A.class /com/example/nested=java.io.BufferedInputStream@addbf1
3: A.class top=null
4: A.class /top=java.io.BufferedInputStream@42e816
5: cl nested=null
6: cl /com/example/nested=null
7: cl com/example/nested=java.io.BufferedInputStream@9304b1
8: cl top=java.io.BufferedInputStream@190d11
9: cl / top=null

В основном все происходит так, как вы ожидаете. Ошибка Case-3 связана с тем, что относительное разрешение класса выполняется по отношению к классу, поэтому "top" означает "/ com / example / top", но " / top" означает то, что там написано.

Ошибка Case-5 завершается с ошибкой, потому что относительное разрешение classloader выполняется по отношению к classloader. Но неожиданно ошибка Case-6 также завершается с ошибкой: можно было бы ожидать, что "/ com / example / nested" разрешится должным образом. Для доступа к вложенному ресурсу через classloader вам нужно использовать Case-7, то есть вложенный путь относительно корня classloader. Аналогично, ошибка Case-9 завершается с ошибкой, но ошибка Case-8 проходит.

Помните: для класса java.lang.getResourceAsStream() делегирует classloader:

 открытый входной поток getResourceAsStream(имя строки) {
name = ResolveName(имя);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// Системный класс.
верните ClassLoader.getSystemResourceAsStream(имя);
}
верните cl.getResourceAsStream(имя);
}

итак, важно поведение ResolveName() .

Наконец, поскольку именно поведение classloader загружает класс, который по существу управляет getResourceAsStream(), а classloader часто является пользовательским загрузчиком, то правила загрузки ресурсов могут быть еще более сложными. например, для веб-приложений загружайте из WEB-INF / classes или WEB-INF / lib в контексте веб-приложения, но не из других изолированных веб-приложений. Кроме того, хорошо управляемые загрузчики классов делегируют родительские права, так что дублирующиеся ресурсы в classpath могут быть недоступны с помощью этого механизма.

Ответ 3

Сначала проверьте свой загрузчик классов.

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

if (classLoader == null) {
classLoader = Class.class.getClassLoader();
}

classLoader.getResourceAsStream("xmlFileNameInJarFile.xml");

// xml file location at xxx.jar
// + folder
// + folder
// xmlFileNameInJarFile.xml
Ответ 4

JAR - это, по сути, ZIP-файл, поэтому относитесь к нему соответственно. Ниже приведен пример того, как извлечь один файл из WAR-файла (также относитесь к нему как к ZIP-файлу) и выводит строковое содержимое. Для двоичного файла вам нужно будет изменить процесс извлечения, но для этого есть множество примеров.

public static void main(String args[]) {
String relativeFilePath = "style/someCSSFile.css";
String zipFilePath = "/someDirectory/someWarFile.war";
String contents = readZipFile(zipFilePath,relativeFilePath);
System.out.println(contents);
}

public static String readZipFile(String zipFilePath, String relativeFilePath) {
try {
ZipFile zipFile = new ZipFile(zipFilePath);
Enumeration<? extends ZipEntry> e = zipFile.entries();

while (e.hasMoreElements()) {
ZipEntry entry = (ZipEntry) e.nextElement();
// if the entry is not directory and matches relative file then extract it
if (!entry.isDirectory() && entry.getName().equals(relativeFilePath)) {
BufferedInputStream bis = new BufferedInputStream(
zipFile.getInputStream(entry));
// Read the file
// With Apache Commons I/O
String fileContentsStr = IOUtils.toString(bis, "UTF-8");

// With Guava
//String fileContentsStr = new String(ByteStreams.toByteArray(bis),Charsets.UTF_8);
// close the input stream.
bis.close();
return fileContentsStr;
} else {
continue;
}
}
} catch (IOException e) {
logger.error("IOError :" + e);
e.printStackTrace();
}
return null;
}

В этом примере я использую Apache Commons I / O, и если вы используете Maven, вот зависимость:

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
java jar