如何在Java中查找与通配符字符串匹配的文件?

时间:2009-04-27 16:59:44

标签: java file wildcard

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

../Test?/sample*.txt

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

我已经看了org.apache.commons.io.filefilter.WildcardFileFilter,它看起来像是正确的野兽,但我不知道如何使用它来查找相对目录路径中的文件。

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

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

17 个答案:

答案 0 :(得分:113)

FileUtilslistFilesiterateFiles方法)尝试Apache commons-io

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

答案 1 :(得分:70)

考虑来自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)。

答案 2 :(得分:43)

以下是按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));
    }

答案 3 :(得分:27)

您可以将通配符字符串转换为正则表达式,并将其与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));

答案 4 :(得分:17)

现在可能没有帮助,但JDK 7的目的是将glob和regex文件名匹配为“更多NIO功能”的一部分。

答案 5 :(得分:16)

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

答案 6 :(得分:12)

通配符库有效地执行glob和regex文件名匹配:

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

实施简洁 - JAR只有12.9千字节。

答案 7 :(得分:10)

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

我创建了以billing_201208.csv,billing_201209.csv,billing_201210.csv命名的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); 
                }
           }
     }    
}

答案 8 :(得分:6)

正如另一个答案所述,通配符库适用于glob和regex文件名匹配:http://code.google.com/p/wildcard/

我使用以下代码来匹配* nix样式文件系统上的包括绝对和相对的glob模式:

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。

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

答案 9 :(得分: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。我没有对此进行过测试,但我确实不断使用模式和文件过滤器。

答案 10 :(得分:4)

Java7的{p> GlobFinding Files。 (Sample

答案 11 :(得分:3)

Apache过滤器用于迭代已知目录中的文件。要同时允许目录中的通配符,您必须在“\”或“/”上拆分路径,并分别对每个部分进行过滤。

答案 12 :(得分:0)

为什么不使用类似的东西:

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

// now you have a fully qualified path

然后你不必担心相对路径,可以根据需要进行通配。

答案 13 :(得分:0)

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

答案 14 :(得分:0)

Util方法:

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class UserAuthorizationAttribute : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(Microsoft.AspNet.Mvc.Filters.AuthorizationContext filterContext)
    {
        filterContext.Controller.ViewData["IdentityUser"] = filterContext.HttpContext.User;
    }
}

jUnit测试:

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

答案 15 :(得分:0)

实现JDK FileVisitor接口。以下是http://wilddiary.com/list-files-matching-a-naming-pattern-java/

的示例

答案 16 :(得分:-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));