2010-10-13 7 views
158

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

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

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

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

+1

Связанный ответ: http://stackoverflow.com/a/30149061/4102160 – Cfx

ответ

121

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

Внесите свой собственный сканер. Например:

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. Более быстрым решением является использование ronmamo's Reflections API, который предварительно компилирует поиск во время компиляции.

+0

Размышления выглядят как отличная идея, но без интеграции IDE это немного ограничивает. – JBCP

+7

, если вы используете Reflections, все, что вам действительно нужно: 'new Reflections (« my.package », new ResourcesScanner()). GetResources (pattern)' – zapp

+8

Выполняется ли первое решение, когда оно выполняется из файла jar? Для меня это не так. Я могу читать файл таким образом, но не могу читать каталог. –

44

Вот код
Источник: 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

Вопросник знает как реализовать его, используя стандартные классы Java, но он хочет знать, как он может использовать существующие библиотеки Spring, Apache Commons. –

+2

'PathMatchingResourcePatternResolver' сделал трюк. – viaclectic

+0

@Jeroen Rosenberg Существует также другой способ, который был выбран окончательно :) –

14

Если вы используете апачский commonsIO вы можете использовать для файловой системы (опционально с расширением фильтра):

Collection<File> files = 
    FileUtils.listFiles(new File("directory/"), null, false); 

и ресурсы/классов:

List<String> files = IOUtils.readLines(MyClass.class.getClassLoader() 
     .getResourceAsStream("directory/"), Charsets.UTF_8); 

Если делать, если "не знает directoy /»находится в файловой системе или в ресурсах вы можете добавить

if(new File("directory/").isDirectory()) 

или

if(MyClass.class.getClassLoader() 
     .getResource("directory/") != null) 

перед вызовами и использовать как в сочетании ...

+14

Файлы! = Ресурсы – djechlin

+3

Конечно, ресурсы не всегда могут быть файлами, но вопрос был о ресурсах, происходящих из файлов/каталогов. Поэтому используйте примерный код, если вы хотите проверить другое местоположение, например. если у вас есть config.xml в ваших ресурсах для некоторой конфигурации по умолчанию, и, возможно, при загрузке внешнего файла config.xml можно будет загрузить внешний файл ... – Rob

+1

И почему ресурсы не являются файлами? Ресурсы - это файлы, архивированные в zip-архив. Они загружаются в память и доступны определенным образом, но я не понимаю, почему они не являются файлами. Любой ресурс, который не является «файлом в архиве»? –

5

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

@Autowired 
ResourcePatternResolver resourceResolver; 

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

Используется сочетание ответа Роба ,

final String resourceDir = "resourceDirectory/"; 
List<String> files = IOUtils.readLines(Thread.currentThread.getClass().getClassLoader().getResourceAsStream(resourceDir), Charsets.UTF_8); 

for(String f : files){ 
    String data= IOUtils.toString(Thread.currentThread.getClass().getClassLoader().getResourceAsStream(resourceDir + f)); 
    ....process data 
} 
10

Использование Google Отражения:

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> fileNames = reflections.getResources(Pattern.compile(".*\\.csv")); 
-3

основе @rob «s выше, я создал реализацию, которую я выпускаю в общественное достояние:

private static List<String> getClasspathEntriesByPath(String path) throws IOException { 
    InputStream is = Main.class.getClassLoader().getResourceAsStream(path); 

    StringBuilder sb = new StringBuilder(); 
    while (is.available()>0) { 
     byte[] buffer = new byte[1024]; 
     sb.append(new String(buffer, Charset.defaultCharset())); 
    } 

    return Arrays 
      .asList(sb.toString().split("\n"))   // Convert StringBuilder to individual lines 
      .stream()         // Stream the list 
      .filter(line -> line.trim().length()>0)  // Filter out empty lines 
      .collect(Collectors.toList());    // Collect remaining lines into a List again 
} 

Хотя я и не ожидал, что getResourcesAsStream будет работать так, как в каталоге, он действительно работает, и он работает хорошо.

+4

вы не читаете InputStream –

0

Spring framework «s PathMatchingResourcePatternResolver действительно удивительным для этих вещей:

private Resource[] getXMLResources() throws IOException 
{ 
    ClassLoader classLoader = MethodHandles.lookup().getClass().getClassLoader(); 
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(classLoader); 

    return resolver.getResources("classpath:x/y/z/*.xml"); 
} 

Maven зависимость:

<dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-core</artifactId> 
    <version>LATEST</version> 
</dependency> 
0

Это должно работать (если весна не вариант):

public static List<String> getFilenamesForDirnameFromCP(String directoryName) throws URISyntaxException, UnsupportedEncodingException, IOException { 
    List<String> filenames = new ArrayList<String>(); 

    URL url = Thread.currentThread().getContextClassLoader().getResource(directoryName); 
    if (url != null) { 
     if (url.getProtocol().equals("file")) { 
      File file = Paths.get(url.toURI()).toFile(); 
      if (file != null) { 
       File[] files = file.listFiles(); 
       if (files != null) { 
        for (File filename : files) { 
         filenames.add(filename.toString()); 
        } 
       } 
      } 
     } else if (url.getProtocol().equals("jar")) { 
      String dirname = directoryName + "/"; 
      String path = url.getPath(); 
      String jarPath = path.substring(5, path.indexOf("!")); 
      try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()))) { 
       Enumeration<JarEntry> entries = jar.entries(); 
       while (entries.hasMoreElements()) { 
        JarEntry entry = entries.nextElement(); 
        String name = entry.getName(); 
        if (name.startsWith(dirname) && !dirname.equals(name)) { 
         URL resource = Thread.currentThread().getContextClassLoader().getResource(name); 
         filenames.add(resource.toString()); 
        } 
       } 
      } 
     } 
    } 
    return filenames; 
} 
Смежные вопросы