2010-07-30 5 views
51

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

+0

см. Http://stackoverflow.com/questions/16842306 – yegor256

+0

Если вы хотите прочитать файлы из каталога в jar с любыми номерами для файлов, см. [Stackoverflow-Link] (https://stackoverflow.com/questions/26185137/ spring-boot-resource-not-found-when-use-executeable-jar/39818817 # 39818817) –

ответ

102

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

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

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

InputStream считывает содержимое вашего файла. Если вы хотите, вы можете обернуть его в Reader.

Я надеюсь, что это поможет.

+17

+1 для объяснения причин, по которым необходимо «/». –

46

А, это один из моих любимых предметов. Существуют два основных способа, которыми Вы можете загрузить ресурс через путь к классам:

Class.getResourceAsStream(resource) 

и

ClassLoader.getResourceAsStream(resource) 

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

Первый метод на самом деле делегирует второй, после изменения имени ресурса. Существует, по существу, два типа имен ресурсов: абсолютный (например, «/ path/to/resource/resource») и относительный (например, «ресурс»). Абсолютные пути начинаются с «/».

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

 
package com.example; 

public class 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); 

     resource = A.class.getResourceAsStream("top"); 
     System.out.println("3: A.class top=" + resource); 

     resource = A.class.getResourceAsStream("/top"); 
     System.out.println("4: A.class /top=" + resource); 

     // ClassLoader.getResourceAsStream 
     ClassLoader cl = A.class.getClassLoader(); 
     resource = cl.getResourceAsStream("nested");   
     System.out.println("5: cl nested=" + resource); 

     resource = cl.getResourceAsStream("/com/example/nested"); 
     System.out.println("6: cl /com/example/nested=" + resource); 
     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); 

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

} 

выход из программы является:

 
1: A.class [email protected] 
2: A.class /com/example/[email protected] 
3: A.class top=null 
4: A.class /[email protected] 
5: cl nested=null 
6: cl /com/example/nested=null 
7: cl com/example/[email protected] 
8: cl [email protected] 
9: cl /top=null 

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

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

Помните: для java.lang.Class, getResourceAsStream() не делегировать загрузчиком классов:

 
    public InputStream getResourceAsStream(String name) { 
     name = resolveName(name); 
     ClassLoader cl = getClassLoader0(); 
     if (cl==null) { 
      // A system class. 
      return ClassLoader.getSystemResourceAsStream(name); 
     } 
     return cl.getResourceAsStream(name); 
    } 

так это поведение resolveName(), что имеет важное значение.

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

+0

Это, по сути, тот же ответ, который я дал, но объяснил многое подробнее. +1 – Mnementh

+0

Вот упомянутый метод resolveName: https://gist.github.com/briangordon/5374626 –

2

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> 
8

Проверьте первый ваш загрузчик классов.

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 
0

Просто для полноты картины, в последнее время был question на Jython, где рассылках один из ответов, указанные в эту тему.

Вопрос заключался в том, чтобы вызвать скрипт на Python, который содержится в файле .jar изнутри Jython, предложенный ответ следующим образом (с «InputStream», как описано в одном из приведенных выше ответов:

PythonInterpreter.execfile(InputStream) 
Смежные вопросы