Вопрос-ответ

Get a list of resources from classpath directory

Получить список ресурсов из каталога classpath

Я ищу способ получить список всех имен ресурсов из данного каталога classpath, что-то вроде метода List<String> getResourceNames (String directoryName).

Например, для заданного каталога classpath, x/y/z содержащего файлы a.html, b.html, c.html и подкаталог d, getResourceNames("x/y/z") должен быть возвращен a List<String> содержащий следующие строки:['a.html', 'b.html', 'c.html', 'd'].

Это должно работать как для ресурсов в файловой системе, так и для jars.

Я знаю, что могу написать быстрый фрагмент с помощью Files, JarFiles и URLs, но я не хочу изобретать велосипед. Мой вопрос в том, что, учитывая существующие общедоступные библиотеки, какой самый быстрый способ реализоватьgetResourceNames? Возможны как стеки Spring, так и Apache Commons.

Переведено автоматически
Ответ 1

Пользовательский сканер

Реализуйте свой собственный сканер. Например:

(ограничения этого решения упоминаются в комментариях)

private List<String> getResourceFiles(String path) throws IOException {
List<String> filenames = new ArrayList<>();

try (
InputStream in = getResourceAsStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
String resource;

while ((resource = br.readLine()) != null) {
filenames.add(resource);
}
}

return filenames;
}

private InputStream getResourceAsStream(String resource) {
final InputStream in
= getContextClassLoader().getResourceAsStream(resource);

return in == null ? getClass().getResourceAsStream(resource) : in;
}

private ClassLoader getContextClassLoader() {
return Thread.currentThread().getContextClassLoader();
}

Spring Framework

Используйте PathMatchingResourcePatternResolver из Spring Framework.

Размышления Ronmamo

Другие методы могут быть медленными во время выполнения при огромных значениях CLASSPATH. Более быстрое решение - использовать Reflections API от ronmamo, который выполняет предварительную компиляцию поиска во время компиляции.

Ответ 2

Вот код

Исходный код: forums.devx.com/showthread.php?t=153784

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

/**
* list resources available from the classpath @ *
*/

public class ResourceList{

/**
* for all elements of java.class.path get a Collection of resources Pattern
* pattern = Pattern.compile(".*"); gets all resources
*
* @param pattern
* the pattern to match
* @return the resources in the order they are found
*/

public static Collection<String> getResources(
final Pattern pattern)
{
final ArrayList<String> retval = new ArrayList<String>();
final String classPath = System.getProperty("java.class.path", ".");
final String[] classPathElements = classPath.split(System.getProperty("path.separator"));
for(final String element : classPathElements){
retval.addAll(getResources(element, pattern));
}
return retval;
}

private static Collection<String> getResources(
final String element,
final Pattern pattern)
{
final ArrayList<String> retval = new ArrayList<String>();
final File file = new File(element);
if(file.isDirectory()){
retval.addAll(getResourcesFromDirectory(file, pattern));
} else{
retval.addAll(getResourcesFromJarFile(file, pattern));
}
return retval;
}

private static Collection<String> getResourcesFromJarFile(
final File file,
final Pattern pattern)
{
final ArrayList<String> retval = new ArrayList<String>();
ZipFile zf;
try{
zf = new ZipFile(file);
} catch(final ZipException e){
throw new Error(e);
} catch(final IOException e){
throw new Error(e);
}
final Enumeration e = zf.entries();
while(e.hasMoreElements()){
final ZipEntry ze = (ZipEntry) e.nextElement();
final String fileName = ze.getName();
final boolean accept = pattern.matcher(fileName).matches();
if(accept){
retval.add(fileName);
}
}
try{
zf.close();
} catch(final IOException e1){
throw new Error(e1);
}
return retval;
}

private static Collection<String> getResourcesFromDirectory(
final File directory,
final Pattern pattern)
{
final ArrayList<String> retval = new ArrayList<String>();
final File[] fileList = directory.listFiles();
for(final File file : fileList){
if(file.isDirectory()){
retval.addAll(getResourcesFromDirectory(file, pattern));
} else{
try{
final String fileName = file.getCanonicalPath();
final boolean accept = pattern.matcher(fileName).matches();
if(accept){
retval.add(fileName);
}
} catch(final IOException e){
throw new Error(e);
}
}
}
return retval;
}

/**
* list the resources that match args[0]
*
* @param args
* args[0] is the pattern to match, or list all resources if
* there are no args
*/

public static void main(final String[] args){
Pattern pattern;
if(args.length < 1){
pattern = Pattern.compile(".*");
} else{
pattern = Pattern.compile(args[0]);
}
final Collection<String> list = ResourceList.getResources(pattern);
for(final String name : list){
System.out.println(name);
}
}
}

Если вы используете Spring, взгляните на PathMatchingResourcePatternResolver

Ответ 3

Использование отражений

Получить все из classpath:

Reflections reflections = new Reflections(null, new ResourcesScanner());
Set<String> resourceList = reflections.getResources(x -> true);

Другой пример - получить все файлы с расширением .csv из some.package:

Reflections reflections = new Reflections("some.package", new ResourcesScanner());
Set<String> resourceList = reflections.getResources(Pattern.compile(".*\\.csv"));

Пожалуйста, обратите внимание: (обновление)

Этот ответ был написан в 2015 году и, вероятно, использовал Reflections 0.9.10. Впоследствии я пробовал более поздние версии библиотеки Reflections и изо всех сил пытался заставить этот ответ работать. Я также изо всех сил пытался заставить работать примеры из их собственной документации... Лично я не уверен, что делают разработчики проекта... Возможно, это ошибка с моей стороны.

Проект Reflections был перенесен из архива кода Google в версии 0.9.9-RC1, как видно [здесь]. В настоящее время проект поддерживается на github [здесь].

Ответ 4

Итак, с точки зрения PathMatchingResourcePatternResolver это то, что необходимо в коде:

@Autowired
ResourcePatternResolver resourceResolver;

public void getResources() {
resourceResolver.getResources("classpath:config/*.xml");
}
java