java - ruta - Obtenga una lista de recursos del directorio classpath
obtener ruta donde se ejecuta la aplicacion java (9)
Estoy buscando una forma de obtener una lista de todos los nombres de recursos de un directorio de ruta de clases determinado, algo así como un método List<String> getResourceNames (String directoryName)
.
Por ejemplo, dado un directorio classpath x/y/z
contiene los archivos a.html
, b.html
, c.html
y un subdirectorio d
, getResourceNames("x/y/z")
debe devolver una List<String>
contenga lo siguiente cadenas: [''a.html'', ''b.html'', ''c.html'', ''d'']
.
Debería funcionar tanto para los recursos en el sistema de archivos como en los archivos jar.
Sé que puedo escribir un fragmento rápido con File
s, JarFile
y URL
s, pero no quiero reinventar la rueda. Mi pregunta es, dadas las bibliotecas públicas disponibles, ¿cuál es la forma más rápida de implementar getResourceNames
? Las pilas de Spring y Apache Commons son factibles.
Escáner personalizado
Implementa tu propio escáner. Por ejemplo:
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();
}
Marco de primavera
Utilice PathMatchingResourcePatternResolver
desde Spring Framework.
Reflexiones de Ronmamo
Las otras técnicas pueden ser lentas en el tiempo de ejecución para grandes valores de CLASSPATH. Una solución más rápida es usar Reflections API de ronmamo, que precompila la búsqueda en tiempo de compilación.
Aquí está el código
Fuente : 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);
}
}
}
Si está utilizando Spring, eche un vistazo a PathMatchingResourcePatternResolver
Basado en la información de @rob anterior, creé la implementación que estoy lanzando al dominio público:
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
}
Si bien no esperaba que getResourcesAsStream
funcionara así en un directorio, realmente funciona y funciona bien.
El PathMatchingResourcePatternResolver
Spring framework
es realmente increíble para estas cosas:
private Resource[] getXMLResources() throws IOException
{
ClassLoader classLoader = MethodHandles.lookup().getClass().getClassLoader();
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(classLoader);
return resolver.getResources("classpath:x/y/z/*.xml");
}
Dependencia de Maven:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>LATEST</version>
</dependency>
Entonces, en términos de PathMatchingResourcePatternResolver esto es lo que se necesita en el código:
@Autowired
ResourcePatternResolver resourceResolver;
public void getResources()
{
resourceResolver.getResources("classpath:config/*.xml");
}
Esto debería funcionar (si la primavera no es una opción):
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;
}
Si usa apache commonsIO, puede usarlo para el sistema de archivos (opcionalmente con filtro de extensión):
Collection<File> files =
FileUtils.listFiles(new File("directory/"), null, false);
y para recursos / classpath:
List<String> files = IOUtils.readLines(MyClass.class.getClassLoader()
.getResourceAsStream("directory/"), Charsets.UTF_8);
Si no sabe si "directorioy /" está en el sistema de archivos o en los recursos, puede agregar un
if( new File("directory/").isDirectory() )
o
if( MyClass.class.getClassLoader()
.getResource("directory/") != null )
antes de las llamadas y usar ambas en combinación ...
Usó una combinación de la respuesta de Rob.
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
}
Usando Google Reflections:
Reflections reflections = new Reflections(null, new ResourcesScanner());
Set<String> resourceList = reflections.getResources(x -> true);
Otra muestra: obtenga todos los archivos con la extensión .csv de some.package :
Reflections reflections = new Reflections("some.package", new ResourcesScanner());
Set<String> fileNames = reflections.getResources(Pattern.compile(".*//.csv"));