Как найти файлы, которые соответствуют подстановочной строке в Java? - PullRequest
133 голосов
/ 27 апреля 2009

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

../Test?/sample*.txt

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

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

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

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

Ответы [ 16 ]

113 голосов
/ 27 апреля 2009

Попробуйте 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 .

70 голосов
/ 30 апреля 2009

Рассмотрим 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();

Вам понадобится ссылка на ant.jar (~ 1,3 МБ для ant 1.7.1).

45 голосов
/ 28 июля 2015

Вот примеры перечисления файлов по шаблону на основе Java 7 nio globbing и 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));
    }
27 голосов
/ 27 апреля 2009

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

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));
17 голосов
/ 29 июня 2016

Начиная с 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")
);
17 голосов
/ 27 апреля 2009

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

12 голосов
/ 16 декабря 2010

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

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

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

10 голосов
/ 05 ноября 2012

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

Я создал 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); </p>

<pre><code>    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); 
                }
           }
     }    
}
</code>

6 голосов
/ 01 февраля 2013

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

Я использовал следующий код для сопоставления шаблонов глобуса, включая абсолютные и относительные в файловых системах стиля * 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 в библиотеке Apache commons io (см. Ответ Владимира), но безуспешно (сейчас я понимаю / думаю, что он может обрабатывать только шаблоны, соответствующие одному каталогу или файлу в время).

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

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

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

5 голосов
/ 08 июля 2011

Вы должны быть в состоянии использовать 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. Я не проверял это, но я постоянно использую шаблоны и файловые фильтры.

...