Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

  • Java IO

    • Java IO概述
    • IO基础

    • 常用IO流

    • 文件与目录操作

      • File类
      • Files与Paths
      • 文件遍历与监听
        • 1. Files.list
        • 2. Files.walk
        • 3. Files.walkFileTree
        • 4. 删除非空目录
        • 5. WatchService
        • 6. WatchService 注意点
        • 专家实践清单
        • Tips 快问快答
        • 7. 总结
      • 临时文件与目录
    • Java NIO

    • 高级主题

    • 实践与性能优化

    • 面试与设计题

    • IO实践速查

  • JVM

目录

文件遍历与监听

实际开发中经常需要遍历目录、查找文件、统计大小,或者监听目录变化。Java NIO.2 提供了比较完整的文件树遍历和目录监听能力。

# 1. Files.list

Files.list 只遍历当前目录一层。

try (Stream<Path> stream = Files.list(Path.of("logs"))) {
    stream
            .filter(Files::isRegularFile)
            .forEach(System.out::println);
}

注意 Stream<Path> 需要关闭,所以要使用 try-with-resources。

# 2. Files.walk

Files.walk 可以递归遍历目录树。

try (Stream<Path> stream = Files.walk(Path.of("logs"))) {
    stream
            .filter(Files::isRegularFile)
            .filter(path -> path.toString().endsWith(".log"))
            .forEach(System.out::println);
}

可以限制遍历深度:

Files.walk(Path.of("logs"), 2);

Files.walk 写法简洁,适合中小规模遍历。超大目录树或需要精细控制异常时,可以使用 walkFileTree。

# 3. Files.walkFileTree

walkFileTree 使用访问者模式遍历文件树。

Files.walkFileTree(Path.of("logs"), new SimpleFileVisitor<>() {
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        if (file.toString().endsWith(".log")) {
            System.out.println(file);
        }
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc) {
        System.err.println("visit failed: " + file);
        return FileVisitResult.CONTINUE;
    }
});

FileVisitResult 可以控制遍历行为:

  • CONTINUE:继续。
  • TERMINATE:终止。
  • SKIP_SUBTREE:跳过当前子树。
  • SKIP_SIBLINGS:跳过同级剩余节点。

# 4. 删除非空目录

删除非空目录可以后序遍历:

Files.walkFileTree(root, new SimpleFileVisitor<>() {
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        Files.delete(file);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
        Files.delete(dir);
        return FileVisitResult.CONTINUE;
    }
});

删除操作有风险,生产环境要增加路径校验、权限控制、日志记录和保护机制。

# 5. WatchService

WatchService 可以监听目录变化。

WatchService watchService = FileSystems.getDefault().newWatchService();
Path dir = Path.of("config");

dir.register(
        watchService,
        StandardWatchEventKinds.ENTRY_CREATE,
        StandardWatchEventKinds.ENTRY_MODIFY,
        StandardWatchEventKinds.ENTRY_DELETE
);

while (true) {
    WatchKey key = watchService.take();
    for (WatchEvent<?> event : key.pollEvents()) {
        System.out.println(event.kind() + " -> " + event.context());
    }
    boolean valid = key.reset();
    if (!valid) {
        break;
    }
}

# 6. WatchService 注意点

  • 监听的是目录,不是单个文件。
  • 默认不递归监听子目录。
  • 不同操作系统实现细节不同。
  • 高频变更可能合并或丢失事件。
  • 生产配置热加载要做防抖和完整性校验。

# 专家实践清单

场景 推荐方式 注意点
列出一级目录 Files.list Stream 要关闭
简单递归遍历 Files.walk 大目录要限制深度
复杂遍历控制 walkFileTree 可处理失败、跳过子树
目录监听 WatchService 不是可靠消息队列

遍历与监听的关系:

首次启动
  │
  ├─ 全量遍历建立初始状态
  ▼
运行期间
  │
  └─ WatchService 监听增量变化

# Tips 快问快答

Q:Files.list 是否递归? A:不递归,只列出当前目录的一级内容。

Q:Files.walk 返回什么? A:返回惰性的 Stream<Path>,需要关闭。

Q:什么时候用 walkFileTree? A:需要精细控制递归、错误处理、跳过目录或访问文件属性时。

Q:遍历大目录最大的风险是什么? A:文件数量巨大导致耗时、内存、句柄和权限问题。

Q:WatchService 能保证不丢事件吗? A:不能。它不是可靠消息系统,高频变更可能合并或丢失。

Q:监听子目录需要额外注册吗? A:通常需要,每个要监听的目录都要注册。

Q:配置热加载为什么要防抖? A:编辑器保存文件可能产生多次事件,防抖能避免重复加载半成品。

Q:可靠同步目录应该只靠 WatchService 吗? A:不应该,通常要结合定期全量校验或扫描补偿。

# 7. 总结

简单遍历使用 Files.list 或 Files.walk,复杂遍历使用 walkFileTree。目录变化监听可以使用 WatchService,但要理解它不是可靠消息队列,不能把它当作强一致事件系统。

上次更新: 2026/06/25, 14:19:18
Files与Paths
临时文件与目录

← Files与Paths 临时文件与目录→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式