Как найти файлы, которые соответствуют шаблону в 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 ответов:
рассмотрим 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
. Я не тестировал это, но я постоянно использую шаблоны и фильтры файлов.
Глоб из Java7: Найти Файлы. (пример)
фильтр 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