7.3 文件系统的遍历
问题
用户希望对文件系统进行深度优先遍历(depth-first traversal)。
方案
使用 java.nio.file.Files 类定义的静态方法 walk。
讨论
walk 方法的签名如下:
- public static Stream<Path> walk(Path start,
- FileVisitOption... options)
- throws IOException
walk 方法的参数为起始 Path 以及 FileVisitOption 值的可变参数列表。从起始路径开始对文件系统执行深度优先遍历,返回一个由 Path 实例惰性填充的 Stream。
由于返回的 Stream 封装了 DirectoryStream,仍然建议在 try-with-resources 代码块中使用 walk 方法,如例 7-7 所示。
例 7-7 文件树的遍历
- try (Stream<Path> paths = Files.walk(Paths.get("src/main/java"))) {
- paths.forEach(System.out::println);
- } catch (IOException e) {
- e.printStackTrace();
- }
walk 方法传入零个或多个 FileVisitOption 值作为第二个参数以及后续参数,不过本例并未使用任何 FileVisitOption 值。FileVisitOption 是 Java 1.7 引入的一种枚举类型,所包含的唯一枚举常量为 FOLLOW_LINKS。至少从理论上说,FOLLOW_LINKS 意味着文件树中可能存在循环,因此流将跟踪所访问的文件。一旦检测到循环,程序将抛出 FileSystemLoopException。
执行本书配套的源代码(例 7-7),输出类似于:
src/main/javasrc/main/java/collectorssrc/main/java/collectors/Actor.javasrc/main/java/collectors/AddCollectionToMap.javasrc/main/java/collectors/Book.javasrc/main/java/collectors/CollectorsDemo.javasrc/main/java/collectors/ImmutableCollections.javasrc/main/java/collectors/Movie.javasrc/main/java/collectors/MysteryMen.javasrc/main/java/concurrencysrc/main/java/concurrency/CommonPoolSize.javasrc/main/java/concurrency/CompletableFutureDemos.javasrc/main/java/concurrency/FutureDemo.javasrc/main/java/concurrency/ParallelDemo.javasrc/main/java/concurrency/SequentialToParallel.javasrc/main/java/concurrency/Timer.javasrc/main/java/datetime...
程序采用惰性方式遍历路径,所生成的流必然包含至少一个元素(起始参数)。对于遇到的每条路径,程序将判断它是否为目录,是则遍历其中的所有条目,然后移动到下一个同级元素(sibling)。其结果是一种深度优先遍历。程序访问每个目录包含的所有条目之后,将关闭该目录。
walk 方法还包括以下重载形式:
- public static Stream<Path> walk(Path start,
- int maxDepth,
- FileVisitOption... options)
- throws IOException
其中,参数 maxDepth 是要访问的目录级别的最大值,0 表示只访问起始文件。如果不使用 maxDepth,可以通过 Integer.MAX_VALUE 值来指定应访问所有级别。
另见
有关如何列出一个目录中的所有文件请参见范例 7.2,有关文件搜索的讨论请参见范例 7.4。
