本Java教程适用于JDK 8。本页面描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java语言更改了解Java SE 9及以后版本中的更新语言特性的摘要。
请参阅JDK版本说明了解所有JDK版本中的新功能、增强和已删除或已弃用选项的信息。
如果你曾经使用过shell脚本,你很可能使用过模式匹配来定位文件。事实上,你可能已经广泛地使用它了。如果你还没有使用过,模式匹配使用特殊字符来创建模式,然后文件名可以与该模式进行比较。例如,在大多数shell脚本中,星号*
匹配任意数量的字符。例如,以下命令列出当前目录中以.html
结尾的所有文件:
% ls *.html
java.nio.file
包为这个有用的功能提供了编程支持。每个文件系统实现都提供了一个PathMatcher
。您可以使用FileSystem
类中的getPathMatcher(String)
方法来检索文件系统的PathMatcher
。下面的代码片段获取了默认文件系统的路径匹配器:
String pattern = ...; PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern);
传递给getPathMatcher
的字符串参数指定了语法风格和要匹配的模式。此示例指定了glob语法。如果你对glob语法不熟悉,请参阅什么是Glob。
Glob语法易于使用且灵活,但如果你喜欢的话,也可以使用正则表达式或regex语法。有关正则表达式的更多信息,请参阅正则表达式教程。某些文件系统实现可能支持其他语法。
如果你想使用其他形式的基于字符串的模式匹配,可以创建自己的PathMatcher
类。本页面的示例使用glob语法。
一旦你创建了PathMatcher
实例,你就可以开始匹配文件了。PathMatcher
接口有一个单一的方法matches
,它接受一个Path
参数并返回一个布尔值:它要么匹配模式,要么不匹配。下面的代码片段查找以.java
或.class
结尾的文件,并将这些文件打印到标准输出:
PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.{java,class}"); Path filename = ...; if (matcher.matches(filename)) { System.out.println(filename); }
搜索与特定模式匹配的文件与遍历文件树密不可分。有多少次您知道文件在文件系统的某个地方,但具体在哪里呢?或者您需要找到文件树中具有特定文件扩展名的所有文件。
Find
示例就是为此而创建的。 Find
类似于UNIX的find
实用程序,但功能减少。您可以扩展此示例以包含其他功能。例如,find
实用程序支持-prune
标志以从搜索中排除整个子树。您可以通过在preVisitDirectory
方法中返回SKIP_SUBTREE
来实现此功能。要实现-L
选项,即遵循符号链接,您可以使用四个参数的walkFileTree
方法,并传递FOLLOW_LINKS
枚举(但请确保在visitFile
方法中检查循环链接)。
要运行Find应用程序,请使用以下格式:
% java Find <path> -name "<glob_pattern>"
模式被放在引号内,以防止shell解释任何通配符。例如:
% java Find . -name "*.html"
以下是Find
示例的源代码:
/** * 查找与指定的glob模式匹配的文件的示例代码。 * 有关什么构成glob模式的详细信息,请参阅 * https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob * * 与模式匹配的文件或目录将打印到标准输出。还将打印匹配的数量。 * * 在执行此应用程序时,必须将glob模式放在引号中,以便Shell不会扩展任何通配符: * java Find . -name "*.java" */ import java.io.*; import java.nio.file.*; import java.nio.file.attribute.*; import static java.nio.file.FileVisitResult.*; import static java.nio.file.FileVisitOption.*; import java.util.*; public class Find { public static class Finder extends SimpleFileVisitor<Path> { private final PathMatcher matcher; private int numMatches = 0; Finder(String pattern) { matcher = FileSystems.getDefault() .getPathMatcher("glob:" + pattern); } // 将glob模式与文件或目录名称进行比较。 void find(Path file) { Path name = file.getFileName(); if (name != null && matcher.matches(name)) { numMatches++; System.out.println(file); } } // 打印匹配的总数到标准输出。 void done() { System.out.println("Matched: " + numMatches); } // 对每个文件调用模式匹配方法。 @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { find(file); return CONTINUE; } // 对每个目录调用模式匹配方法。 @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { find(dir); return CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { System.err.println(exc); return CONTINUE; } } static void usage() { System.err.println("java Find <path>" + " -name \"<glob_pattern>\""); System.exit(-1); } public static void main(String[] args) throws IOException { if (args.length < 3 || !args[1].equals("-name")) usage(); Path startingDir = Paths.get(args[0]); String pattern = args[2]; Finder finder = new Finder(pattern); Files.walkFileTree(startingDir, finder); finder.done(); } }
递归遍历文件树的内容在遍历文件树中有介绍。