Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

332
Views
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 answers
Answer question

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!