180

这应该很简单。如果我有这样的字符串:

../Test?/sample*.txt

那么获取与此模式匹配的文件列表的普遍接受的方法是什么?(例如它应该匹配../Test1/sample22b.txtand../Test4/sample-spiffy.txt但不匹配../Test3/sample2.blahor ../Test44/sample2.txt

我看了看,org.apache.commons.io.filefilter.WildcardFileFilter它似乎是正确的野兽,但我不确定如何使用它在相对目录路径中查找文件。

我想我可以查看 ant 的源代码,因为它使用通配符语法,但我必须在这里遗漏一些非常明显的东西。

编辑:上面的例子只是一个示例案例。我正在寻找在运行时解析包含通配符的一般路径的方法。我根据 mmyers 的建议想出了如何做到这一点,但这有点烦人。更不用说java JRE似乎从单个参数自动解析main(String []参数)中的简单通配符以“节省”我的时间和麻烦......我很高兴我没有非文件参数混合。)

4

17 回答 17

140

FileUtilsApache commons-iolistFilesiterateFiles方法)尝试:

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

于 2009-04-27T19:13:38.000 回答
88

考虑来自 Apache Ant 的 DirectoryScanner:

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

您需要参考 ant.jar(ant 1.7.1 约为 1.3 MB)。

于 2009-04-30T05:55:10.673 回答
69

以下是由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));
    }
于 2015-07-28T19:39:38.383 回答
32

从 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")
);
于 2016-06-29T14:23:35.600 回答
30

您可以将通配符字符串转换为正则表达式并将其与 String 的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));
于 2009-04-27T19:04:00.473 回答
18

现在可能对您没有帮助,但 JDK 7 旨在将 glob 和正则表达式文件名匹配作为“更多 NIO 功能”的一部分。

于 2009-04-27T17:25:57.060 回答
13

通配符库有效地进行 glob 和正则表达式文件名匹配:

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

实现很简洁——JAR 只有 12.9 KB。

于 2010-12-16T01:42:08.557 回答
12

不使用任何外部导入的简单方法是使用此方法

我创建了名为 billing_201208.csv 、billing_201209.csv 、billing_201210.csv 的 csv 文件,它看起来工作正常。

如果上面列出的文件存在,输出将如下

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

    //使用导入 -> 导入 java.io.File
        公共静态无效主要(字符串[]参数){
        字符串 pathToScan = ".";
        字符串目标文件;// fileThatYouWantToFilter
        文件夹ToScan = 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); 
                }
           }
     }    
}

于 2012-11-05T07:45:56.650 回答
6

正如在另一个答案中发布的那样,通配符库适用于 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();

我花了一些时间试图让 Apache commons io 库中的 FileUtils.listFiles 方法(请参阅 Vladimir 的答案)来做到这一点,但没有成功(我现在意识到/认为它一次只能处理匹配一个目录或文件的模式) .

此外,使用正则表达式过滤器(参见 Fabian 的回答)来处理任意用户提供的绝对类型 glob 模式而不搜索整个文件系统将需要对提供的 glob 进行一些预处理以确定最大的非正则表达式/glob 前缀。

当然,Java 7 可以很好地处理请求的功能,但不幸的是,我现在被 Java 6 困住了。该库相对较小,只有 13.5kb。

审稿人注意:我试图将上述内容添加到提及此库的现有答案中,但编辑被拒绝。我也没有足够的代表将此添加为评论。有没有更好的办法...

于 2013-02-01T00:11:53.093 回答
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

于 2011-07-07T23:55:52.527 回答
5

Java7 的Glob查找文件。(样本

于 2013-06-03T13:02:33.060 回答
3

Apache 过滤器是为迭代已知目录中的文件而构建的。要在目录中也允许使用通配符,您必须在 ' \' 或 ' /' 上拆分路径并分别对每个部分进行过滤。

于 2009-04-27T17:02:49.923 回答
1

仅使用 Java 流

Path testPath = Paths.get("C:\");

Stream<Path> stream =
                Files.find(testPath, 1,
                        (path, basicFileAttributes) -> {
                            File file = path.toFile();
                            return file.getName().endsWith(".java");
                        });

// Print all files found
stream.forEach(System.out::println);
于 2019-04-05T21:12:20.577 回答
0

为什么不使用做类似的事情:

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

// now you have a fully qualified path

这样您就不必担心相对路径,并且可以根据需要进行通配符。

于 2009-04-27T17:07:07.150 回答
0

实现 JDK FileVisitor 接口。这是一个示例http://wilddiary.com/list-files-matching-a-naming-pattern-java/

于 2014-12-16T15:36:40.490 回答
0

使用方法:

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
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
于 2016-01-23T19:37:40.483 回答
-1

使用 io 库的 File 类最简单易行的方法是:

    String startingdir="The directory name";
    String filenameprefix="The file pattern"
    File startingDirFile=new File(startingdir); 
    final File[] listFiles=startingDirFile.listFiles(new FilenameFilter() {
        public boolean accept(File arg0,String arg1)
        {System.out.println(arg0+arg1);
            return arg1.matches(filenameprefix);}
        });
    System.out.println(Arrays.toString(listFiles));
于 2021-05-18T19:22:34.953 回答