java 8 引入的 java.nio.file.files 类提供了 files.walk() 方法来遍历目录。该方法返回一个 stream<path></path>,支持流式处理文件路径,可以方便地过滤和收集结果。

Files.walk() 如何处理符号链接?
Files.walk() 默认会跟随符号链接(Symbolic Links)。如果目录结构中存在循环引用或需要避免重复处理,可以通过设置 FileVisitOption.FOLLOW_LINKS 来控制行为,但默认情况下它会自动解析并进入链接指向的目标。

import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;
public class DirectoryWalker {
public static void main(String[] args) throws IOException {
Path startPath = Paths.get("/tmp/test_dir");
// 使用 Files.walk() 遍历目录,默认跟随符号链接
try (Stream<Path> paths = Files.walk(startPath)) {
paths.forEach(System.out::println);
}
}
}
运行上述代码,若 /tmp/test_dir 下包含普通文件和子目录,输出将按深度优先顺序列出所有路径。如果存在符号链接,且目标在遍历范围内,也会被访问。
立即学习“Java免费学习笔记(深入)”;
Files.list() 与 Files.walk() 的区别是什么?
Files.list() 仅返回指定目录下的直接子项(文件和子目录),不递归深入子目录。而 Files.walk() 是递归遍历整个目录树。如果需要扁平化获取某一层级的内容,应使用 list();如果需要全量遍历,则用 walk()。

import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;
public class ListVsWalk {
public static void main(String[] args) throws IOException {
Path dir = Paths.get("/tmp/test_dir");
// 仅列出当前目录下的直接子项
try (Stream<Path> listed = Files.list(dir)) {
System.out.println("Listed items:");
listed.forEach(p -> System.out.println(" " + p));
}
// 递归遍历所有子项
try (Stream<Path> walked = Files.walk(dir)) {
System.out.println("Walked items:");
walked.forEach(p -> System.out.println(" " + p));
}
}
}
对比运行结果:Files.list() 只输出第一层条目,而 Files.walk() 会输出包括子目录在内的所有嵌套路径。注意两者都返回 Stream<path></path>,需确保在使用完毕后关闭流,推荐使用 try-with-resources 语法。
当目录中包含大量文件时,Files.walk() 的性能表现如何?
Files.walk() 在遇到极深或极大目录树时可能产生大量内存占用,因为它会将所有路径加载到 Stream 中。对于超大目录,建议结合 limit()、filter() 等中间操作尽早终止遍历,或使用 Files.find() 进行更精细的控制。


















