Comment trouver des fichiers qui correspondent à une chaîne de caractères en Java?

cela devrait être vraiment simple. Si j'ai une chaîne comme celle-ci:

../Test?/sample*.txt

alors quelle est une façon généralement acceptée d'obtenir une liste de fichiers qui correspondent à ce modèle? (par exemple, il doit correspondre à ../Test1/sample22b.txt et ../Test4/sample-spiffy.txt mais pas à ../Test3/sample2.blah ou ../Test44/sample2.txt )

j'ai jeté un oeil à org.apache.commons.io.filefilter.WildcardFileFilter et il semble comme la bonne bête, mais je ne sais pas comment l'utiliser pour trouver des fichiers dans un répertoire relatif chemin.

je suppose que je peux chercher la source pour ant puisqu'il utilise la syntaxe de Joker, mais je dois manquer quelque chose assez évident ici.

( edit : l'exemple ci-dessus n'était qu'un cas type. Je cherche le moyen de parcourir les chemins généraux contenant des caractères génériques à l'exécution. J'ai trouvé comment le faire en me basant sur la suggestion de mmyers mais c'est un peu agaçant. Sans oublier que le java JRE semble auto-analyser des jokers simples dans le main (String[] arguments) à partir d'un seul argument pour me "sauver" le temps et les tracas... Je suis juste content de ne pas avoir d'arguments non-classés dans le mix.)

119
demandé sur Jason S 2009-04-27 20:59:44

15 réponses

Envisager 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();

vous devez faire référence à ant.jar (~1.3 MB pour ant 1.7.1).

68
répondu Misha 2009-04-30 05:55:10

Essayer FileUtils à partir de Apache commons-io ( listFiles et iterateFiles méthodes):

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]);
}

pour résoudre votre problème avec les dossiers TestX , je voudrais d'abord itérer à travers la liste des dossiers:

File[] dirs = new File(".").listFiles(new WildcardFileFilter("Test*.java");
for (int i=0; i<dirs.length; i++) {
   File dir = dirs[i];
   if (dir.isDirectory()) {
       File[] files = dir.listFiles(new WildcardFileFilter("sample*.java"));
   }
}

tout à fait une solution de "force brute" mais devrait fonctionner très bien. Si cela ne correspond pas à vos besoins, vous pouvez toujours utiliser le RegexFileFilter .

107
répondu Vladimir 2017-12-06 02:01:22

Voici des exemples de listes de fichiers par modèle alimenté par Java 7 nio globbing et Java 8 lambdas:

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

ou

    PathMatcher pathMatcher = FileSystems.getDefault()
        .getPathMatcher("regex:Test.[\/]sample\w+\.txt");
    try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(
            new File("..").toPath(), pathMatcher::matches)) {
        dirStream.forEach(path -> System.out.println(path));
    }
37
répondu Vadzim 2017-05-23 12:17:59

vous pouvez convertir votre chaîne de caractères génériques en une expression régulière et utiliser la méthode matches de String. Suivant votre exemple:

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

cela fonctionne pour vos exemples:

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

et contre-exemples:

Assert.assertTrue(!"../Test3/sample2.blah".matches(regex));
Assert.assertTrue(!"../Test44/sample2.txt".matches(regex));
27
répondu Fabian Steeg 2009-04-27 19:04:00

pourrait ne pas vous aider en ce moment, mais JDK 7 est destiné à avoir le nom de fichier glob et regex correspondant dans le cadre de"plus de fonctionnalités NIO".

17
répondu Tom Hawtin - tackline 2012-05-31 21:42:00

depuis Java 8, Vous pouvez utiliser la méthode Files#find directement à partir de java.nio.file .

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

exemple d'usage

Files.find(startingPath,
           Integer.MAX_VALUE,
           (path, basicFileAttributes) -> path.toFile().getName().matches(".*.pom")
);
13
répondu Grzegorz Gajos 2016-06-29 14:23:35

la bibliothèque wildcard fait efficacement la correspondance des noms de fichiers glob et regex:

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

l'implémentation est succincte -- JAR n'est que de 12,9 kilo-octets.

12
répondu NateS 2010-12-16 01:42:08

méthode Simple sans utiliser d'importation externe est d'utiliser cette méthode

j'ai créé des fichiers csv nommés avec billing_201208.csv, billing_201209.csv, billing_201210.csv et il semble bien fonctionner.

sortie sera la suivante si les fichiers énumérés ci-dessus existe

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

    //Use Import ->import 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); 
                }
           }
     }    
}

9
répondu Umair Aziz 2013-01-21 02:34:20

comme posté dans une autre réponse, la bibliothèque wildcard fonctionne à la fois pour glob et regex correspondance de nom de fichier: http://code.google.com/p/wildcard /

j'ai utilisé le code suivant pour faire correspondre les motifs glob incluant absolu et relatif sur les systèmes de fichiers de style nix:

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();

j'ai passé du temps à essayer d'obtenir les FileUtils.méthodes listFiles dans la bibliothèque io d'Apache commons (voir la réponse de Vladimir) pour faire ceci mais n'avait pas succès (je réalise maintenant/je pense qu'il ne peut gérer que le motif correspondant à un répertoire ou à un fichier à la fois).

de plus, l'utilisation de filtres regex (voir la réponse de Fabian) pour le traitement des motifs de type absolu fournis par l'utilisateur sans effectuer de recherche dans l'ensemble du système de fichiers nécessiterait un prétraitement de la glob fournie pour déterminer le plus grand préfixe Non-regex/glob.

bien sûr, Java 7 peut gérer la fonctionnalité demandée correctement, mais malheureusement, je suis coincé avec Java 6 pour l'instant. La bibliothèque est relativement minuscule à 13,5 ko.

Note aux réviseurs: j'ai essayé d'ajouter la réponse ci-dessus à la réponse existante mentionnant cette bibliothèque, mais l'édition a été rejetée. Je n'ai pas assez de réputation pour ajouter ceci comme commentaire. N'est-il pas une meilleure façon...

6
répondu Oliver Coleman 2013-02-01 00:11:53

vous devriez pouvoir utiliser le WildcardFileFilter . Suffit d'utiliser System.getProperty("user.dir") pour obtenir le répertoire de travail. Essayez ceci:

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

vous ne devriez pas avoir à remplacer * par [.*] , en supposant que le filtre de Joker utilise java.regex.Pattern . Je n'ai pas testé cela, mais j'utilise des modèles et des filtres de fichiers constamment.

5
répondu Anonymous 2011-07-08 04:27:44
4
répondu 卢声远 Shengyuan Lu 2013-06-03 13:02:33

le filtre Apache est construit pour itérer des fichiers dans un répertoire connu. Pour permettre les caractères génériques dans le répertoire aussi, vous devez diviser le chemin sur ' \ ' ou ' / ' et faire un filtre sur chaque partie séparément.

3
répondu Michael Myers 2009-04-27 17:02:49

Pourquoi ne pas faire quelque chose comme:

File myRelativeDir = new File("../../foo");
String fullPath = myRelativeDir.getCanonicalPath();
Sting wildCard = fullPath + File.separator + "*.txt";

// now you have a fully qualified path

alors vous n'aurez pas à vous soucier des chemins relatifs et pouvez faire votre wildcarding si nécessaire.

0
répondu Elijah 2009-04-27 17:07:07

implémenter l'interface JDK FileVisitor. Voici un exemple http://wilddiary.com/list-files-matching-a-naming-pattern-java/

0
répondu Drona 2014-12-16 15:36:40

Méthode 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);

    }

test de jUnit:

@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));
        }
    }
}

sortie:

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
0
répondu Tony 2016-01-23 19:37:40