¿Cómo encontrar archivos que coincidan con una cadena comodín en Java?

Esto debería ser realmente simple. Si tengo una cadena como esta:

../Test?/sample*.txt 

entonces, ¿cuál es una forma generalmente aceptada de obtener una lista de archivos que coinciden con este patrón? (Por ejemplo, debe coincidir con ../Test1/sample22b.txt y ../Test4/sample-spiffy.txt pero no con ../Test3/sample2.blah o ../Test44/sample2.txt )

He echado un vistazo a org.apache.commons.io.filefilter.WildcardFileFilter y parece ser la bestia correcta, pero no estoy seguro de cómo usarla para buscar archivos en una ruta de directorio relativa.

Supongo que puedo buscar el origen de la ant ya que usa la syntax comodín, pero me falta algo bastante obvio aquí.

( Editar : el ejemplo anterior fue solo un caso de muestra. Estoy buscando la forma de analizar las rutas generales que contienen comodines en tiempo de ejecución. Me di cuenta de cómo hacerlo basándome en la sugerencia de mmyers, pero es un poco molesto. Sin mencionar que el java JRE parece analizar automáticamente comodines simples en el argumento principal (String []) de un único argumento para “salvarme” el tiempo y la molestia … Estoy contento de no haber tenido argumentos sin archivos en el mezcla.)

Considere DirectoryScanner de Apache Ant:

 DirectoryScanner scanner = new DirectoryScanner(); scanner.setIncludes(new String[]{"**/*.java"}); scanner.setBasedir("C:/Temp"); scanner.setCaseSensitive(false); scanner.scan(); String[] files = scanner.getIncludedFiles(); 

Tendrá que hacer referencia a ant.jar (~ 1.3 MB para ant 1.7.1).

Pruebe FileUtils desde Apache commons-io (métodos listFiles y iterateFiles ):

 File dir = new File("."); FileFilter fileFilter = new WildcardFileFilter("sample*.java"); File[] files = dir.listFiles(fileFilter); for (int i = 0; i < files.length; i++) { System.out.println(files[i]); } 

Para resolver su problema con las carpetas de TestX , primero iteraría a través de la lista de carpetas:

 File[] dirs = new File(".").listFiles(new WildcardFileFilter("Test*.java"); for (int i=0; i 

Bastante una solución de "fuerza bruta", pero debería funcionar bien. Si esto no se ajusta a sus necesidades, siempre puede usar RegexFileFilter .

Aquí hay ejemplos de listados de archivos por patrones impulsados ​​por Java 7 nio globbing y Java 8 lambdas:

  try (DirectoryStream dirStream = Files.newDirectoryStream( Paths.get(".."), "Test?/sample*.txt")) { dirStream.forEach(path -> System.out.println(path)); } 

o

  PathMatcher pathMatcher = FileSystems.getDefault() .getPathMatcher("regex:Test.[\\/]sample\\w+\\.txt"); try (DirectoryStream dirStream = Files.newDirectoryStream( new File("..").toPath(), pathMatcher::matches)) { dirStream.forEach(path -> System.out.println(path)); } 

Puede convertir su cadena comodín en una expresión regular y usarla con el método de matches de String. Siguiendo tu ejemplo:

 String original = "../Test?/sample*.txt"; String regex = original.replace("?", ".?").replace("*", ".*?"); 

Esto funciona para tus ejemplos:

 Assert.assertTrue("../Test1/sample22b.txt".matches(regex)); Assert.assertTrue("../Test4/sample-spiffy.txt".matches(regex)); 

Y contra ejemplos:

 Assert.assertTrue(!"../Test3/sample2.blah".matches(regex)); Assert.assertTrue(!"../Test44/sample2.txt".matches(regex)); 

Puede que no lo ayude en este momento, pero JDK 7 está destinado a tener correspondencia de nombre de archivo global y regular como parte de “Más funciones de NIO”.

La biblioteca de comodines hace de forma eficiente coincidencias de nombre de archivo glob y regex:

http://code.google.com/p/wildcard/

La implementación es sucinta: JAR tiene solo 12.9 kilobytes.

Desde Java 8 puede usar Files#find method directamente desde java.nio.file .

 public static Stream find(Path start, int maxDepth, BiPredicate matcher, FileVisitOption... options) 

Ejemplo de uso

 Files.find(startingPath, Integer.MAX_VALUE, (path, basicFileAttributes) -> path.toFile().getName().matches(".*.pom") ); 

Manera simple sin usar ninguna importación externa es usar este método

Creé archivos csv nombrados con billing_201208.csv, billing_201209.csv, billing_201210.csv y parece funcionar bien.

La salida será la siguiente si existen archivos mencionados anteriormente

 found billing_201208.csv found billing_201209.csv found billing_201210.csv 

     // Usar Importar -> importar java.io.File
         public static void main (String [] args) {
         String pathToScan = ".";
         String target_file;  // fileThatYouWantToFilter
         File folderToScan = new File (pathToScan); 

  File[] listOfFiles = folderToScan.listFiles(); for (int i = 0; i < listOfFiles.length; i++) { if (listOfFiles[i].isFile()) { target_file = listOfFiles[i].getName(); if (target_file.startsWith("billing") && target_file.endsWith(".csv")) { //You can add these files to fileList by using "list.add" here System.out.println("found" + " " + target_file); } } } } 

Tal como se publicó en otra respuesta, la biblioteca de comodines funciona para la coincidencia de nombre de archivo gloge y regex: http://code.google.com/p/wildcard/

Utilicé el siguiente código para unir los patrones globales, incluidos los sistemas de archivos de estilo absoluto y relativo en:

 String filePattern = String baseDir = "./"; // If absolute path. TODO handle windows absolute path? if (filePattern.charAt(0) == File.separatorChar) { baseDir = File.separator; filePattern = filePattern.substring(1); } Paths paths = new Paths(baseDir, filePattern); List files = paths.getFiles(); 

Pasé un tiempo tratando de obtener los métodos FileUtils.listFiles en la biblioteca de Apache commons io (ver la respuesta de Vladimir) para hacer esto pero no tuve éxito (me doy cuenta ahora / creo que solo puede manejar patrones que coincidan con un directorio o archivo a la vez) .

Además, el uso de filtros regex (ver la respuesta de Fabian) para procesar patrones glob de tipo absoluto suministrados arbitrariamente por el usuario sin buscar todo el sistema de archivos requeriría un preprocesamiento del glob proporcionado para determinar el prefijo no regex / glob más grande.

Por supuesto, Java 7 puede manejar la funcionalidad solicitada muy bien, pero desafortunadamente estoy atascado con Java 6 por ahora. La biblioteca es relativamente minúscula con un tamaño de 13.5kb.

Nota para los revisores: intenté agregar lo anterior a la respuesta existente mencionando esta biblioteca pero la edición fue rechazada. No tengo suficientes representantes para agregar esto como un comentario tampoco. ¿No hay una mejor manera …

Debería poder usar WildcardFileFilter . Simplemente use System.getProperty("user.dir") para obtener el directorio de trabajo. Prueba esto:

 public static void main(String[] args) { File[] files = (new File(System.getProperty("user.dir"))).listFiles(new WildcardFileFilter(args)); //... } 

No debería necesitar reemplazar * con [.*] , Suponiendo que el filtro comodín usa java.regex.Pattern . No lo he probado, pero utilizo patrones y filtros de archivos constantemente.

Glob of Java7: Encontrar archivos . ( Muestra )

El filtro Apache está diseñado para iterar archivos en un directorio conocido. Para permitir comodines en el directorio también, debe dividir la ruta en ‘ \ ‘ o ‘ / ‘ y hacer un filtro en cada parte por separado.

Por qué no usar hacer algo como:

 File myRelativeDir = new File("../../foo"); String fullPath = myRelativeDir.getCanonicalPath(); Sting wildCard = fullPath + File.separator + "*.txt"; // now you have a fully qualified path 

Entonces no tendrás que preocuparte por las rutas relativas y puedes hacer tus comodines según sea necesario.

Implemente la interfaz JDK FileVisitor. Aquí hay un ejemplo de http://wilddiary.com/list-files-matching-a-naming-pattern-java/

Método de Util:

 public static boolean isFileMatchTargetFilePattern(final File f, final String targetPattern) { String regex = targetPattern.replace(".", "\\."); //escape the dot first regex = regex.replace("?", ".?").replace("*", ".*"); return f.getName().matches(regex); } 

jUnit Test:

 @Test public void testIsFileMatchTargetFilePattern() { String dir = "D:\\repository\\org\my\\modules\\mobile\\mobile-web\\b1605.0.1"; String[] regexPatterns = new String[] {"_*.repositories", "*.pom", "*-b1605.0.1*","*-b1605.0.1", "mobile*"}; File fDir = new File(dir); File[] files = fDir.listFiles(); for (String regexPattern : regexPatterns) { System.out.println("match pattern [" + regexPattern + "]:"); for (File file : files) { System.out.println("\t" + file.getName() + " matches:" + FileUtils.isFileMatchTargetFilePattern(file, regexPattern)); } } } 

Salida:

 match pattern [_*.repositories]: mobile-web-b1605.0.1.pom matches:false mobile-web-b1605.0.1.war matches:false _remote.repositories matches:true match pattern [*.pom]: mobile-web-b1605.0.1.pom matches:true mobile-web-b1605.0.1.war matches:false _remote.repositories matches:false match pattern [*-b1605.0.1*]: mobile-web-b1605.0.1.pom matches:true mobile-web-b1605.0.1.war matches:true _remote.repositories matches:false match pattern [*-b1605.0.1]: mobile-web-b1605.0.1.pom matches:false mobile-web-b1605.0.1.war matches:false _remote.repositories matches:false match pattern [mobile*]: mobile-web-b1605.0.1.pom matches:true mobile-web-b1605.0.1.war matches:true _remote.repositories matches:false