Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

345
Vistas
Enumere todos los archivos de un directorio que coincidan con una máscara de archivo (también conocida como patrón o globo)

Quiero enumerar todos los archivos en un directorio y subdirectorios dentro de ese directorio que coincidan con una máscara de archivo .

Por ejemplo, "M:\SOURCE\*.doc", mientras que SOURCE puede verse así:

 |-- SOURCE | |-- Folder1 | | |-- File1.doc | | |-- File1.txt | |-- File2.doc | |-- File3.xml

Debería devolver File1.doc y File2.doc.

Inicialmente, uso un DirectoryStream , porque eso ya hace algunas comprobaciones de la sintaxis de máscara/glob, además de poder usarlo para filtrar, ya que NO ES solo una expresión regular, sino una máscara de archivo real que un usuario normal encuentra más fácil de entender.

 Files.newDirectoryStream(path, mask);

El problema es que DirectoryStream solo verifica el directorio de ruta inmediata que proporciona y no sus subdirectorios

ENTONCES viene un método de "aplanamiento" con Files.walk que de hecho es capaz de mirar a través de todos los subdirectorios, el problema es que NO brinda la posibilidad de "filtrar" por una máscara de archivo de la misma manera que lo hace un DirectoryStream

 Files.walk(path, Integer.MAX_VALUE);

Así que estoy atascado, incapaz de combinar lo mejor de ambos métodos aquí...

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

También puede usar FileVisitor personalizado [1], con una combinación de PathMatcher [2], que funciona perfectamente con GLOB.

El código podría verse así:

 public static void main(String[] args) throws IOException { System.out.println(getFiles(Paths.get("/tmp/SOURCE"), "*.doc")); } public static List<Path> getFiles(final Path directory, final String glob) throws IOException { final var docFileVisitor = new GlobFileVisitor(glob); Files.walkFileTree(directory, docFileVisitor); return docFileVisitor.getMatchedFiles(); } public static class GlobFileVisitor extends SimpleFileVisitor<Path> { private final PathMatcher pathMatcher; private List<Path> matchedFiles = new ArrayList<>(); public GlobFileVisitor(final String glob) { this.pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + glob); } @Override public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException { if (pathMatcher.matches(path.getFileName())) { matchedFiles.add(path); } return FileVisitResult.CONTINUE; } public List<Path> getMatchedFiles() { return matchedFiles; } }

[1] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileVisitor.html

[2] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/PathMatcher.html

over 4 years ago · Santiago Trujillo Denunciar

0

Creo que podría haber resuelto mi propia pregunta con la información recibida aquí y otras preguntas que mencionan el objeto PathMatcher

 final PathMatcher maskMatcher = FileSystems.getDefault() .getPathMatcher("glob:" + mask); final List<Path> matchedFiles = Files.walk(path) .collect(Collectors.toList()); final List<Path> filesToRemove = new ArrayList<>(matchedFiles.size()); matchedFiles.forEach(foundPath -> { if (!maskMatcher.matches(foundPath.getFileName()) || Files.isDirectory(foundPath)) { filesToRemove.add(foundPath); } }); matchedFiles.removeAll(filesToRemove);

Así que básicamente .getPathMatcher("glob:" + mask); es lo mismo que estaba haciendo DirectoryStream para filtrar los archivos

Todo lo que tengo que hacer ahora es filtrar la lista de rutas que obtengo con Files.walk eliminando los elementos que no coinciden con mi PathMatcher y que no son del tipo File

over 4 years ago · Santiago Trujillo Denunciar

0

Es posible usar el filter de flujo común para recuperar los nombres de archivo filtrados de Files.walk usando String::matches con la expresión regular adecuada:

 final String SOURCE_DIR = "test"; Files.walk(Paths.get(SOURCE_DIR)); .filter(p -> p.getFileName().toString().matches(".*\\.docx?")) .forEach(System.out::println);

Producción

 test\level01\level11\test.doc test\level02\test-level2.doc test\t1.doc test\t3.docx

Estructura del directorio de entrada:

 │ t1.doc │ t2.txt │ t3.docx │ t4.bin │ ├───level01 │ │ test.do │ │ │ └───level11 │ test.doc │ └───level02 test-level2.doc

Actualizar

Es posible una solución recursiva utilizando newDirectoryStream , sin embargo, debe convertirse en Stream:

 static Stream<Path> readFilesByMaskRecursively(Path start, String mask) { List<Stream<Path>> sub = new ArrayList<>(); try { sub.add(StreamSupport.stream( // read files by mask in current dir Files.newDirectoryStream(start, mask).spliterator(), false)); Files.newDirectoryStream(start, (path) -> path.toFile().isDirectory()) .forEach(path -> sub.add(recursive(path, mask))); } catch (IOException ioex) { ioex.printStackTrace(); } return sub.stream().flatMap(s -> s); // convert to Stream<Path> } // test readFilesByMaskRecursively(Paths.get(SOURCE_DIR), "*.doc*") .forEach(System.out::println);

Producción:

 test\t1.doc test\t3.docx test\level01\level11\test.doc test\level02\test-level2.doc

Actualización 2

Se puede agregar un prefijo **/ al PathMatcher para cruzar los límites del directorio, luego la solución basada en Files.walk puede usar un filtro simplificado sin la necesidad de eliminar entradas específicas:

 String mask = "*.doc*"; PathMatcher maskMatcher = FileSystems.getDefault().getPathMatcher("glob:**/" + mask); Files.walk(Paths.get(SOURCE_DIR)) .filter(path -> maskMatcher.matches(path)) .forEach(System.out::println);

Salida (igual que en la solución recursiva):

 test\level01\level11\test.doc test\level02\test-level2.doc test\t1.doc test\t3.docx
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda