Как прочитать файл из jar в Java? - PullRequest
55 голосов
/ 30 июля 2010

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

Ответы [ 5 ]

105 голосов
/ 30 июля 2010

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

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

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

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

Надеюсь, это поможет.

52 голосов
/ 31 июля 2010

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

Class.getResourceAsStream(resource)

и

ClassLoader.getResourceAsStream(resource)

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

Первый метод фактически делегирует второму после искажения имени ресурса. Существуют два вида имен ресурсов: абсолютные (например, «/ path / to / resource / 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 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» означает то, что говорится.

Case-5 завершается неудачно, потому что относительное разрешение загрузчика классов относится к загрузчику классов. Но неожиданно 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);
    }

так что важно поведение resolName ().

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

8 голосов
/ 12 февраля 2013

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

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
2 голосов
/ 23 октября 2012

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>
0 голосов
/ 30 октября 2014

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

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

PythonInterpreter.execfile(InputStream)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...