paths和files不是java.io.file的升级版,而是为解决其路径拼接、原子操作和异常语义缺陷而设计;混用易致nullpointerexception或filesystemexception。

Paths 和 Files 不是替代 java.io.File 的“升级版”,而是为了解决它在路径拼接、原子操作和异常语义上的硬伤——用错场景或混用旧 API,反而更容易出 NullPointerException 或 FileSystemException。
Paths.get() 为什么不能直接当文件路径字符串用
Paths.get() 返回的是 Path 对象,不是 String。常见错误是把它传给老式 API(比如 FileInputStream 构造函数)或日志打印时没调用 .toString(),结果输出类似 sun.nio.fs.WindowsPath@1b6d3586 这种哈希值。
- 需要字符串路径时,必须显式调用
path.toString()(注意:这不是标准化路径,可能含..)或path.toAbsolutePath().normalize().toString() - 跨平台拼接路径务必用
Paths.get("a", "b", "c"),别用"a" + File.separator + "b"—— 后者在模块化项目里可能因File类不可见而编译失败 -
Paths.get("")是合法的,但对应当前工作目录;Paths.get(".")才明确表示当前目录,语义更清晰
Files.exists() 和 Files.notExists() 的语义陷阱
这两个方法不互为反义词。当路径存在但无法访问(比如权限不足、挂载点失效),Files.exists(path) 返回 false,Files.notExists(path) 也返回 false —— 二者都可能返回 false,这是设计使然,不是 bug。
- 判断“确定存在且可读”要组合使用:
Files.exists(p) && Files.isReadable(p) - 检查是否存在时,建议加
LinkOption.NOFOLLOW_LINKS参数避免意外跟随符号链接:Files.exists(path, LinkOption.NOFOLLOW_LINKS) - 不要用
!Files.exists()替代Files.notExists(),后者会尝试排除“访问被拒”等中间态,语义更准
Files.copy() 的覆盖行为和流泄漏风险
Files.copy() 默认不覆盖目标文件,抛 FileAlreadyExistsException。但即使加了 StandardCopyOption.REPLACE_EXISTING,如果目标是目录,它也不会自动删除再重建——而是直接失败。
立即学习“Java免费学习笔记(深入)”;
- 复制到已存在目录需手动处理:
if (Files.isDirectory(target)) Files.delete(target); Files.copy(source, target, REPLACE_EXISTING) - 从
InputStream复制时(如Files.copy(in, path, ...)),in不会被自动关闭,必须由调用方负责;推荐改用Files.copy(sourcePath, targetPath, ...)避免流管理 - 大文件复制慎用
Files.readAllBytes()+Files.write(),内存占用翻倍,且无进度反馈;Files.copy()底层用堆外缓冲,更稳
用 Files.walk() 遍历时的并发与符号链接坑
Files.walk() 返回的是懒加载的 Stream<path></path>,一旦底层文件树变动(比如遍历时另一个线程删了子目录),可能抛 DirectoryIteratorException —— 它不是 RuntimeException,得显式捕获。
- 默认会跟随符号链接,导致重复遍历或无限循环;如需跳过,加参数:
Files.walk(path, FileVisitOption.FOLLOW_LINKS)改成EnumSet.noneOf(FileVisitOption.class) - 流未消费完就退出(比如
findFirst()后没close()),可能导致句柄泄漏;务必用 try-with-resources 包裹:try (Stream<path> s = Files.walk(p)) { ... }</path> - 深度限制用
Files.walk(p, maxDepth),但注意:maxDepth = 1只遍历子项,不包含根路径本身
最麻烦的其实是混合使用 Path 和 File:比如把 path.toFile() 的结果传给 Files 方法,看似能跑,但在 Windows 网络路径或 Java 17+ 的强封装模式下,toFile() 可能返回 null 或抛 UnsupportedOperationException。











