Как найти файлы, которые соответствуют шаблону в Java?


это должно быть очень простой. Если у меня есть строка, как это:

../Test?/sample*.txt

тогда каков общепринятый способ получить список файлов, которые соответствуют этому шаблону? (например, он должен соответствовать ../Test1/sample22b.txt и ../Test4/sample-spiffy.txt а не ../Test3/sample2.blah или ../Test44/sample2.txt)

Я взглянул на org.apache.commons.io.filefilter.WildcardFileFilter и это кажется правильным зверем, но я не уверен, как использовать его для поиска файлов в относительном пути к каталогу.

Я полагаю, что могу найти источник для муравья поскольку он использует синтаксис подстановочных знаков, но я должен упустить что-то довольно очевидное здесь.

(edit: приведенный выше пример был просто примером. Я ищу способ разбора общих путей, содержащих подстановочные знаки во время выполнения. Я понял, как это сделать, основываясь на предложении mmyers, но это немного раздражает. Не говоря уже о том, что java JRE, похоже, автоматически анализирует простые подстановочные знаки в основном(String[] arguments) из одного аргумента, чтобы "сэкономить" мне время и хлопоты... Я просто рад, что у меня не было аргументов без файлов в миксе.)

15 119

15 ответов:

рассмотрим DirectoryScanner от Apache Ant:

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

вам нужно будет ссылаться на муравья.jar (~ 1.3 MB для ant 1.7.1).

попробовать FileUtils С Apache commons-io (listFiles и 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]);
}

чтобы решить вашу проблему с TestX папки, я бы сначала перебрал список папок:

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

довольно "грубой силы" решение, но должно работать нормально. Если это не соответствует вашим потребностям, вы всегда можете использовать RegexFileFilter.

вот примеры листинга файлов по шаблону на базе Java 7 nioподстановка и Java 8 lambdas:

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

или

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

вы можете преобразовать свою строку подстановочных знаков в регулярное выражение и использовать его со строкой matches метод. Следуя вашему примеру:

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

это работает для вашего примера:

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

и контр-примеры:

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

может не помочь вам прямо сейчас, но JDK 7 предназначен для сопоставления имен файлов glob и regex в рамках "дополнительных функций NIO".

начиная с Java 8 вы можете использовать Files#find способ прямо из java.nio.file.

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

пример использования

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

библиотеки по шаблону эффективно как Глоб и сопоставления регулярных выражений именем:

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

реализация сжата -- JAR составляет всего 12,9 килобайт.

простой способ без использования внешнего импорта-использовать этот метод

Я создал csv файлы с именем с billing_201208.csv, billing_201209.csv, billing_201210.csv и похоже, что работает нормально.

вывод будет следующим, если файлы, перечисленные выше, существуют

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

как указано в другом ответе, библиотека подстановочных знаков работает как для сопоставления файлов glob, так и для регулярных выражений:http://code.google.com/p/wildcard/

я использовал следующий код для сопоставления шаблонов glob, включая абсолютные и относительные файловые системы в стиле * 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();

Я потратил некоторое время, пытаясь получить FileUtils.методы listFiles в библиотеке io Apache commons (см. ответ Владимира), чтобы сделать это, но не имели успеха (я понимаю сейчас/думаю, что это может только обрабатывать шаблон, соответствующий одному каталогу или файлу за раз).

кроме того, использование фильтров регулярных выражений (см. ответ Фабиана) для обработки произвольных шаблонов глобуса абсолютного типа, предоставленных Пользователем, без поиска всей файловой системы потребует некоторой предварительной обработки предоставленного глобуса для определения самого большого префикса без регулярного выражения/глобуса.

конечно, Java 7 может обрабатывать запрошенную функциональность красиво, но, к сожалению, я застрял с Java 6 на данный момент. Библиотека является относительно мизер в 13,5 КБ.

Примечание для рецензентов: я попытался добавить выше к существующему ответу, упомянув эту библиотеку, но редактирование было отклонено. У меня недостаточно репутации, чтобы добавить это в качестве комментария. Разве нет лучшего способа...

вы должны быть в состоянии использовать WildcardFileFilter. Просто используйте System.getProperty("user.dir") чтобы получить рабочий каталог. Попробуйте это:

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

вы не должны заменить * С [.*], предполагая, что подстановочный фильтр использует java.regex.Pattern. Я не тестировал это, но я постоянно использую шаблоны и фильтры файлов.

фильтр Apache построен для итерации файлов в известном каталоге. Чтобы разрешить подстановочные знаки в каталоге также, вам придется разделить путь на '\' или '/ и сделать фильтр на каждую часть отдельно.

почему бы не использовать сделать что-то вроде:

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

// now you have a fully qualified path

тогда тебе не придется беспокоиться о относительных путей и может сделать ваш подстановочных знаков по мере необходимости.

реализовать интерфейс JDK FileVisitor. Вот пример http://wilddiary.com/list-files-matching-a-naming-pattern-java/

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

выход:

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