Как прочитать файл из jar в Java?
Я хочу прочитать файл XML, который находится внутри одного из jar
s включены в мой путь к классу. Как я могу прочитать любой файл, который включен в jar
?
7 ответов
Если вы хотите прочитать этот файл из своего приложения, используйте:
InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");
Путь начинается с "/", но это не путь в вашей файловой системе, а в вашем пути к классам. Поэтому, если ваш файл находится в classpath "org.xml" и называется myxml.xml, ваш путь выглядит как "/org/xml/myxml.xml".
InputStream читает содержимое вашего файла. Вы можете обернуть его в ридер, если хотите.
Надеюсь, это поможет.
Ах, это одна из моих любимых тем. Существуют два способа загрузки ресурса через путь к классам:
Class.getResourceAsStream(resource)
а также
ClassLoader.getResourceAsStream(resource)
(есть другие способы, которые включают получение URL-адреса для ресурса аналогичным образом, а затем открытие соединения с ним, но это два прямых способа).
Первый метод фактически делегирует второму после искажения имени ресурса. Существуют два вида имен ресурсов: абсолютные (например, "/ path / to / resource / resource") и относительные (например, "resource"). Абсолютные пути начинаются с "/".
Вот пример, который должен проиллюстрировать. Рассмотрим класс com.example.A. Рассмотрим два ресурса, один из которых расположен в / com / example / nested, а другой - в / top, в пути к классам. Следующая программа показывает девять возможных способов доступа к двум ресурсам:
пакет com.example; открытый класс A { public static void main (String args []) { // Class.getResourceAsStream Object resource = A.class.getResourceAsStream ("nested"); System.out.println ("1: A.class nested =" + resource); resource = A.class.getResourceAsStream ("/ com / example / nested"); System.out.println ("2: A.class / com / example / nested =" + ресурс); resource = A.class.getResourceAsStream ("top"); System.out.println ("3: A.class top =" + ресурс); resource = A.class.getResourceAsStream ("/ top"); System.out.println ("4: A.class / top =" + ресурс); // ClassLoader.getResourceAsStream ClassLoader cl = A.class.getClassLoader (); resource = cl.getResourceAsStream ("nested"); System.out.println ("5: cl nested =" + ресурс); resource = cl.getResourceAsStream ("/ com / example / nested"); System.out.println ("6: cl / com / example / nested =" + ресурс); resource = cl.getResourceAsStream ("com / example / nested"); System.out.println ("7: cl com / example / nested =" + resource); resource = cl.getResourceAsStream ("top"); System.out.println ("8: cl top =" + ресурс); resource = cl.getResourceAsStream ("/ top"); System.out.println ("9: cl / top =" + ресурс); } }
Вывод из программы:
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
Главным образом вещи делают то, что вы ожидаете. Случай 3 завершается неудачно, поскольку относительное разрешение класса относится к классу, поэтому "top" означает "/ com / example / top", а "/ top" означает то, что говорится.
Случай 5 терпит неудачу, потому что относительное разрешение загрузчика классов относится к загрузчику классов. Но неожиданно Case-6 также дает сбой: можно ожидать, что "/ com / example / nested" разрешится правильно. Чтобы получить доступ к вложенному ресурсу через загрузчик классов, вам нужно использовать Case-7, то есть вложенный путь относительно корня загрузчика классов. Аналогично, Case-9 дает сбой, но Case-8 проходит.
Помните: для java.lang.Class, getResourceAsStream() делегирует загрузчику классов:
public InputStream getResourceAsStream (String name) { name = resolName(name); ClassLoader cl = getClassLoader0(); if (cl==null) { // Системный класс. return ClassLoader.getSystemResourceAsStream(name); } return cl.getResourceAsStream(name); }
поэтому важно поведение resolName().
Наконец, поскольку поведение загрузчика классов загружает класс, который по существу управляет getResourceAsStream(), а загрузчик классов часто является пользовательским загрузчиком, то правила загрузки ресурсов могут быть еще более сложными. например, для веб-приложений загрузите из WEB-INF/classes или WEB-INF/lib в контексте веб-приложения, но не из других изолированных веб-приложений. Кроме того, хорошо ведущие себя загрузчики классов делегируют родителям, так что дублированные ресурсы в пути к классам могут быть недоступны при использовании этого механизма.
Сначала проверьте ваш класс загрузчик.
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
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, и если вы используете Maven, вот зависимость:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
Это также работает на весне
ClassPathResource resource = new ClassPathResource("/file.txt", MainApplication.class); //resources folder
InputStream inputStream = resource.getInputStream();
File file = new File("file.txt");
FileUtils.copyInputStreamToFile(inputStream, file);
Просто для полноты, недавно в списке рассылки Jython возник вопрос, где один из ответов относится к этой теме.
Вопрос заключался в том, как вызвать скрипт Python, содержащийся в файле.jar, изнутри Jython. Предложенный ответ следующий (с "InputStream", как объяснено в одном из ответов выше:
PythonInterpreter.execfile(InputStream)
Вот как я читаю файл из jar.
Файл, который я хочу прочитать, находится вне банки, в папке ресурсов приложения.
try(InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("common/test.yaml")) {
//Your code
} catch (Exception e) {
LOGGER.error(e);
}
Как я уже сказал, файл находится в папке ресурсов, и у меня также есть подпапки.