Files.deleteIfExists() 是原子性删除方法,通过单次系统调用完成“检查+删除”,避免TOCTOU竞态条件、减少系统调用开销,并返回布尔值简化错误处理,但仅对单文件或空目录原子,非空目录需递归处理。

Files.deleteIfExists() 是 Java NIO.2 提供的原子性删除方法,它在单次系统调用中完成“检查是否存在 + 删除”的逻辑,相比先调用 Files.exists() 再调用 Files.delete() 的两步模式,在并发场景下具有明确的线程安全优势。
避免竞态条件(TOCTOU)
经典两步法存在典型的“Time-of-Check-Time-of-Use”漏洞:
- 线程 A 调用
exists()返回true,准备删除; - 此时线程 B 执行了
delete()或move(),目标文件已被移除或重命名; - 线程 A 继续执行
delete(),抛出NoSuchFileException(或静默失败,取决于逻辑)。
deleteIfExists() 将判断与删除交由底层操作系统(如 Linux 的 unlink())一次性完成:若文件存在则删,不存在则直接成功返回,不抛异常——整个过程不可分割,天然规避 TOCTOU。
减少系统调用开销
两步法至少触发两次系统调用(stat() + unlink()),而 deleteIfExists() 通常只触发一次(unlink())。即使文件不存在,现代内核对 unlink() 的不存在路径也做了快速失败优化,实际开销远低于两次独立调用。
语义更简洁、错误处理更可控
两步法需手动组合逻辑:
- 若
exists() == false,是否跳过?是否记录日志? - 若
delete()失败(权限不足、正被占用等),是重试、忽略,还是中断流程?
deleteIfExists() 统一返回 boolean:仅表示“本次是否发生了删除动作”,不因“文件本就不存在”而报错。开发者只需关注真正需要处理的异常(如 AccessDeniedException、DirectoryNotEmptyException),逻辑更聚焦。
注意:原子性仅限单文件,不扩展到目录树
deleteIfExists() 对单个路径(文件或空目录)是原子的;但若用于非空目录,它会失败(抛 DirectoryNotEmptyException),不递归删除。若需递归删除,应使用 Files.walkFileTree() 配合自定义 FileVisitor,此时原子性需自行保障(通常依赖文件系统级锁或应用层协调)。

















