Чтение каталога внутри JAR с помощью InputStreamReader

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

Я хочу перечислить все файлы внутри каталога внутри JAR приложения, поэтому в IDE это работает:

File f = new File(this.getClass().getResource("/resources/").getPath());

for(String s : f.list){
   System.out.println(s);
}

Это дает мне все файлы внутри каталога.

Теперь я пробовал это также:

InputStream in = this.getClass().getClassLoader().getResourceAsStream("resources/");
    InputStreamReader inReader = new InputStreamReader(in);
    Scanner scan = new Scanner(inReader);

    while (scan.hasNext()) {
        String s = scan.next();
        System.out.println("read: " + s);
    }

    System.out.println("END OF LINE");

И из IDE он печатает ВСЕ файлы в каталоге. Снаружи IDE печатает: «КОНЕЦ СТРОКИ».

Теперь я также могу найти запись в банке с этим:

        String s = new File(this.getClass().getResource("").getPath()).getParent().replaceAll("(!|file:\\\\)", "");
        JarFile jar = new JarFile(s);

            JarEntry entry = jar.getJarEntry("resources");

        if (entry != null){
            System.out.println("EXISTS");
            System.out.println(entry.getSize());
        }

Это какое-то ужасное кодирование, которое мне пришлось сделать с этой строкой.

В любом случае... Я не могу получить список ресурсов внутри каталога "resources" в Jar... Как я могу это сделать???


person Jh62    schedule 15.08.2013    source источник


Ответы (2)


Невозможно просто получить отфильтрованный список внутренних ресурсов без предварительного перечисления содержимого файла Jar.

К счастью, на самом деле это не так сложно (и, к счастью для меня, вы проделали большую часть тяжелой работы).

По сути, когда у вас есть ссылка на JarFile, вам просто нужно запросить его entries и перебрать этот список.

Проверив имя JarEntry на требуемое совпадение (т.е. resources), вы можете отфильтровать нужные элементы...

Например...

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ReadMyResources {

    public static void main(String[] args) {
        new ReadMyResources();
    }

    public ReadMyResources() {
        JarFile jf = null;
        try {            
            String s = new File(this.getClass().getResource("").getPath()).getParent().replaceAll("(!|file:\\\\)", "");
            jf = new JarFile(s);

            Enumeration<JarEntry> entries = jf.entries();
            while (entries.hasMoreElements()) {
                JarEntry je = entries.nextElement();
                if (je.getName().startsWith("resources")) {
                    System.out.println(je.getName());
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                jf.close();
            } catch (Exception e) {
            }
        }
    }

}

Осторожно

Этот тип вопроса на самом деле задают немного. Вместо того, чтобы пытаться прочитать содержимое Jar во время выполнения, было бы лучше создать какой-то текстовый файл, содержащий список доступных ресурсов.

Это может быть создано вашим процессом сборки динамически до создания файла Jar. Было бы гораздо более простым решением прочитать этот файл (например, через getClass().getResource()), а затем просмотреть каждый список ресурсов в текстовом файле... ИМХО

person MadProgrammer    schedule 15.08.2013
comment
Спасибо за ответ и последнее замечание. По иронии судьбы, я пришел к тому же решению, прежде чем вернуться сюда, чтобы прочитать ответы. Я думаю, это лучший способ, тогда. Также другим способом было бы создать временную папку со всеми ресурсами, которые вам нужно читать во время выполнения во временной папке. - person Jh62; 15.08.2013
comment
Я бы сказал, что использование ресурсов в качестве внешних ресурсов, вероятно, является более простым решением. Использование решения со списком файлов может позволить вам фактически развернуть несколько списков ресурсов (с одним и тем же) в нескольких банках. Вам придется объединить их, но это будет означать, что вы можете получить доступ к ресурсам в нескольких банках, не зная, где они на самом деле хранятся. - person MadProgrammer; 15.08.2013
comment
@MadProgrammer, не могли бы вы предоставить ссылку, которая демонстрирует это, чтобы перечислить все файлы в процессе сборки? - person supertonsky; 09.06.2017
comment
@supertonsky Это будет зависеть от того, какой процесс сборки вы используете. Ant может это сделать, Maven должен это сделать, иначе вам придется делать это вручную - person MadProgrammer; 09.06.2017
comment
@MadProgrammer, maven должен быть в порядке :) - person supertonsky; 09.06.2017
comment
@supertonsky Вам, вероятно, придется написать новый плагин;) - По сути, между фазами сборки и упаковки вам нужно сгенерировать еще один файл, который представляет собой список необходимых вам ресурсов - так что мои 10 секунд исследования повернул это, в котором перечислены несколько способов, которыми вы могли бы быть в состоянии сделать это - person MadProgrammer; 09.06.2017

Для пользователей Spring Framework просмотрите PathMatchingResourcePatternResolver, чтобы сделать что-то вроде следующего:

PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:path/to/resource/*.*");

for (Resource resource : resources) {
    InputStream inStream = resource.getInputStream();
    // Do something with the input stream
}
person solimant    schedule 15.05.2018
comment
Так просто и работает как шарм! Спасибо! На мой взгляд, это должен быть правильный ответ. Вам не нужно быть пользователем Spring, чтобы использовать это, просто возьмите банку Spring... - person jhas; 17.09.2018