Obter uma lista de resources do diretório classpath

Eu estou procurando uma maneira de obter uma lista de todos os nomes de resources de um determinado diretório de caminho de class, algo como um método List getResourceNames (String directoryName) .

Por exemplo, dado um diretório de caminho de class x/y/z contendo arquivos a.html , b.html , c.html e um subdiretório d , getResourceNames("x/y/z") deve retornar uma List contendo o seguinte strings: ['a.html', 'b.html', 'c.html', 'd'] .

Deve funcionar tanto para resources em filesystems quanto em jars.

Eu sei que posso escrever um trecho rápido com os File s, JarFile URL s, mas eu não quero reinventar a roda. Minha pergunta é, dadas as bibliotecas disponíveis publicamente existentes, qual é a maneira mais rápida de implementar o getResourceNames ? As pilhas Spring e Apache Commons são possíveis.

Scanner Personalizado

Implemente seu próprio scanner. Por exemplo:

  private List getResourceFiles( String path ) throws IOException { List 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

Use o PathMatchingResourcePatternResolver do Spring Framework.

Reflexões de Ronmamo

As outras técnicas podem ser lentas em tempo de execução para grandes valores de CLASSPATH. Uma solução mais rápida é usar a API Reflections do ronmamo, que pré-compila a pesquisa em tempo de compilation.

Aqui está o código
Fonte : 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 getResources( final Pattern pattern){ final ArrayList retval = new ArrayList(); 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 getResources( final String element, final Pattern pattern){ final ArrayList retval = new ArrayList(); 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 getResourcesFromJarFile( final File file, final Pattern pattern){ final ArrayList retval = new ArrayList(); 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 getResourcesFromDirectory( final File directory, final Pattern pattern){ final ArrayList retval = new ArrayList(); 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 list = ResourceList.getResources(pattern); for(final String name : list){ System.out.println(name); } } } 

Se você estiver usando o Spring, dê uma olhada no PathMatchingResourcePatternResolver

Se você usa o apache commonsIO, você pode usar para o sistema de arquivos (opcionalmente com o filtro de extensão):

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

e para resources / caminho de class:

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

Se você não sabe se “directoy /” está no sistema de arquivos ou em resources, você pode adicionar um

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

ou

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

antes das chamadas e usar os dois em combinação …

Usando o Google Reflections:

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

Outra amostra: obtenha todos os arquivos com extensão .csv de algum pacote :

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

Portanto, em termos do PathMatchingResourcePatternResolver, isso é o que é necessário no código:

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

Usado uma combinação da resposta de Rob.

 final String resourceDir = "resourceDirectory/"; List 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 } 

O PathMatchingResourcePatternResolver Spring framework é realmente incrível para essas coisas:

 private Resource[] getXMLResources() throws IOException { ClassLoader classLoader = MethodHandles.lookup().getClass().getClassLoader(); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(classLoader); return resolver.getResources("classpath:x/y/z/*.xml"); } 

Dependência Maven:

  org.springframework spring-core LATEST  

Isso deve funcionar (se a primavera não for uma opção):

 public static List getFilenamesForDirnameFromCP(String directoryName) throws URISyntaxException, UnsupportedEncodingException, IOException { List filenames = new ArrayList(); 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 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; } 

Com base nas informações do @rob acima, criei a implementação que estou lançando para o domínio público:

 private static List 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 } 

Embora eu não esperasse que o getResourcesAsStream funcionasse assim em um diretório, ele realmente funciona e funciona bem.