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

Я хочу прочитать файл XML, который находится внутри одного из jars включены в мой путь к классу. Как я могу прочитать любой файл, который включен в 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);
        }

Как я уже сказал, файл находится в папке ресурсов, и у меня также есть подпапки.

Другие вопросы по тегам