Как правильно использовать ClassLoader.getResources ()?

Как я могу использовать ClassLoader.getResources() для рекурсивного поиска ресурсов из моего пути к классам?

E.g.

  • поиск всех ресурсов в META-INF "каталоге": представьте себе что-то вроде

    getClass().getClassLoader().getResources("META-INF")

    К сожалению, это возвращает только URL именно в этот "каталог".

  • все ресурсы с именем bla.xml (рекурсивно)

    getClass().getClassLoader().getResources("bla.xml")

    Но это возвращает пустой Enumeration.

И как бонусный вопрос: чем ClassLoader.getResources() отличается от ClassLoader.getResource()?


person MRalwasser    schedule 04.03.2011    source источник
comment
@Andrew, многие фреймворки выполняют итерацию для некоторых файлов на основе имени или расширений в архивах для автоматизации некоторых процессов, таких как поиск ActionBeans of Stripes или файлов hbm.xml для спящего режима.   -  person bestsss    schedule 04.03.2011
comment
См. stackoverflow.com/questions/1429172/   -  person Vadzim    schedule 24.08.2012
comment
Причина, по которой вас это смущает, заключается в том, что getResources работает с загрузчиком классов, который может иметь несколько JAR в пути к классам. Итак, если у вас есть несколько JAR с одним и тем же ресурсом, вы получите все. Однако он НЕ предназначен для поиска внутри каталогов. С помощью getResources (META-INF) вы получаете все каталоги META-INFO в пути поиска CL, и если CL является загрузчиком классов одного файла jar, вы получите не более одной записи.   -  person eckes    schedule 23.05.2014


Ответы (5)


Нет возможности рекурсивного поиска по пути к классам. Вам необходимо знать полный путь к ресурсу, чтобы получить его таким образом. Ресурс может находиться в каталоге в файловой системе или в файле jar, поэтому это не так просто, как выполнение списка каталогов «пути к классам». Вам нужно будет указать полный путь к ресурсу, например. '/com/mypath/bla.xml'.

Что касается вашего второго вопроса, getResource вернет первый ресурс, который соответствует заданному имени ресурса. Порядок поиска пути к классам указан в javadoc для getResource.

person krock    schedule 04.03.2011
comment
Нет возможности рекурсивного поиска по пути к классам ... Конечно, это возможно. Например: URLClassLoader.getURLs(). Откройте JarFile, выполните итерацию. - person bestsss; 04.03.2011
comment
@bestsss: что, если URL-адрес указывает не на JarFile, а на каталог? - person MRalwasser; 04.03.2011
comment
@bestsss, @MRalwasser: или даже хуже, если он указывает на URL-адрес HTTP? - person Joachim Sauer; 04.03.2011
comment
;) ну, загрузчик классов может быть просто подклассом java.lang.ClassLoader без URL-адреса, во всяком случае. Он может генерировать классы в памяти и так далее. У него может быть очень настраиваемый getResource и т. Д. @MRalwasser, если он указывает на какую-то файловую систему, которую вы обрабатываете таким образом, это простой сценарий. @Joachim, кроме апплетов, сейчас нет случаев, когда файлы хранятся удаленно. URL-адрес может быть любым, но пока это один JAR-адрес, вы не можете получить банку из http. случаи. - person bestsss; 04.03.2011

В Spring Framework есть класс, который позволяет рекурсивно выполнять поиск по пути к классам:

PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
resolver.getResources("classpath*:some/package/name/**/*.xml");
person rec    schedule 24.06.2013
comment
Если вы пытаетесь разрешить ресурсы в банке и не знаете, как должен выглядеть шаблон, запустите jar tf myjar.jar. Я закончил с PathMatchinResourcePatternResolver("definitions/**/*.json"). - person MatrixManAtYrService; 15.12.2017
comment
что на самом деле означает classpath*: предполагается ли, что это должно быть заменено полностью определенным содержимым текущего пути к классам для поиска? - person WestCoastProjects; 05.01.2020
comment
Если существует более одного JAR, содержащего один и тот же ресурс, то предполагается, что classpath:my/resource.xml вызовет ошибку, а classpath*:my/resource.xml вернет оба. Подробнее см., Например, tech-tauk.blogspot.com/2010/04/ - person rec; 06.01.2020

Это самый простой способ получить объект File, на который указывает определенный объект URL:

File file=new File(url.toURI());

Теперь по вашим конкретным вопросам:

  • поиск всех ресурсов в "директории" META-INF:

Вы действительно можете получить объект File, указывающий на этот URL

Enumeration<URL> en=getClass().getClassLoader().getResources("META-INF");
if (en.hasMoreElements()) {
    URL metaInf=en.nextElement();
    File fileMetaInf=new File(metaInf.toURI());

    File[] files=fileMetaInf.listFiles();
    //or 
    String[] filenames=fileMetaInf.list();
}
  • все ресурсы с именем bla.xml (рекурсивно)

В этом случае вам придется написать собственный код. Вот фиктивный пример:

final List<File> foundFiles=new ArrayList<File>();

FileFilter customFilter=new FileFilter() {
    @Override
    public boolean accept(File pathname) {

        if(pathname.isDirectory()) {
            pathname.listFiles(this);
        }
        if(pathname.getName().endsWith("bla.xml")) {
            foundFiles.add(pathname);
            return true;
        }
        return false;
    }

};      
//rootFolder here represents a File Object pointing the root forlder of your search 
rootFolder.listFiles(customFilter);

Когда код будет запущен, вы получите все найденные вхождения в foundFiles List.

person Tomas Narros    schedule 04.03.2011
comment
Я сомневаюсь, что это сработает в любых случаях для всех типов загрузчиков классов (например, классов в jar-файлах). - person MRalwasser; 29.03.2011
comment
Я тестировал, получаю исключение: java.lang.IllegalArgumentException: URI не иерархический. Вы не можете создать объект File из непрозрачного URI, такого как jar: ... - person cn1h; 19.03.2012

Вот код, основанный на ответе bestsss:

    Enumeration<URL> en = getClass().getClassLoader().getResources(
            "META-INF");
    List<String> profiles = new ArrayList<>();
    while (en.hasMoreElements()) {
        URL url = en.nextElement();
        JarURLConnection urlcon = (JarURLConnection) (url.openConnection());
        try (JarFile jar = urlcon.getJarFile();) {
            Enumeration<JarEntry> entries = jar.entries();
            while (entries.hasMoreElements()) {
                String entry = entries.nextElement().getName();
                System.out.println(entry);
            }
        }
    }
person Mark Butler    schedule 11.03.2013
comment
Такая структура меня сначала смутила. Кажется, что единственная цель getClass (). GetClassLoader (). GetResources (META-INF) - получить ссылку на какой-то произвольный файл в банке, которую мы затем используем для получения JarURLConnection. Первоначально я думал, что это будет перебирать файлы в каталоге META-INF, но на самом деле он перебирает каждый отдельный файл во всей банке. - person Alex Pritchard; 29.11.2013
comment
У меня это не работает. Он показывает только содержимое первого jar-файла J в пути к классу, так что J содержит запись, которая начинается с path, присвоенного методу getResources(path). Таким образом, результат вашего фрагмента кода является неполным и зависит от порядка элементов в пути к классу. Итак, @krock был прав, когда сказал, что нет возможности рекурсивного поиска по пути к классам - person Readren; 23.04.2016
comment
Извините за комментарий necro, но это действительно работает. Единственная проблема заключалась в том, что оператор if должен быть на некоторое время. - person Buddha Buddy; 21.01.2020

MRalwasser, я дам вам подсказку, переведите URL.getConnection() в JarURLConnection. Затем используйте JarURLConnection.getJarFile () и вуаля! У вас есть JarFile, и вы можете свободно получать доступ к ресурсам внутри.

Остальное оставляю вам.

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

person Community    schedule 04.03.2011
comment
Что вы имеете в виду под URL.getConnection()? Я все равно не могу найти этот метод. - person m0skit0; 30.06.2016