file.exists() 返回 true 不代表可读写,需组合检查权限与状态;mkdirs() 可能静默失败,应检查返回值或改用 files.createdirectories();listfiles() 返回 null 需前置校验;delete() 在 windows 上可能静默失败,推荐 files.delete()。

File.exists() 判断路径存在但不等于可操作
很多开发者调用 exists() 返回 true 就默认能读写,实际可能因权限、挂载状态或符号链接断裂导致后续 canRead() 或 createNewFile() 失败。尤其在 Linux 容器或 Windows 网络驱动器中常见。
- 务必组合检查:
file.exists() && file.canRead()(读场景)或file.getParentFile().canWrite()(写场景) -
exists()对符号链接只检测链路本身是否存在,不验证目标;用Files.exists(path, LinkOption.NOFOLLOW_LINKS)更可控 - Android 上从 API 29 起,
File对应用私有目录外的路径限制加剧,exists()可能静默返回false即使路径物理存在
mkdirs() 不抛异常但可能部分创建成功
mkdirs() 声称“创建所有必需父目录”,但若中间某级目录已存在且是文件(而非目录),它不会报错,而是直接返回 false,最终子目录未创建——这个返回值常被忽略。
- 永远检查返回值:
if (!dir.mkdirs()) { /* 这里必须处理失败 */ } - 更安全的做法是改用
Files.createDirectories(path),它在任何失败时都抛IOException,且自动处理原子性与竞态条件 - 注意
mkdirs()不保证线程安全;多线程并发调用同一路径时,可能触发重复创建尝试,需外层加锁或改用Files的原子方法
listFiles() 返回 null 的三种真实原因
listFiles() 在以下情况返回 null:路径不存在、路径存在但不是目录、当前进程无读取权限。它不会告诉你具体是哪一种,容易引发 NullPointerException。
- 调用前必须先确认:
file.exists() && file.isDirectory() && file.canRead() - 替代方案优先用
Files.list(path)(返回Stream<path></path>),它对每种错误都抛明确异常,如NotDirectoryException或AccessDeniedException - 如果必须用
listFiles(),记得判空:File[] children = dir.listFiles(); if (children == null) throw new IllegalStateException("Cannot list " + dir);
File.delete() 在 Windows 上可能静默失败
Windows 下若文件正被其他进程(包括 JVM 自身的 FileInputStream 未关闭、IDE 文件监视器、杀毒软件)占用,delete() 直接返回 false,不抛异常,也不提示原因。
立即学习“Java免费学习笔记(深入)”;
- 删除前确保流已关闭,推荐用 try-with-resources;检查是否被自己持有引用(如 static File 字段缓存了已删除路径)
- 临时文件建议用
Files.delete(path),它在失败时抛FileSystemException,消息中常含“being used by another process”等线索 - 需要强制删除时,可先调用
Files.move(path, path.resolveSibling("tmp_" + path.getFileName()), StandardCopyOption.REPLACE_EXISTING)绕过占用,再删重命名后的文件
File 类的多数方法都依赖底层 OS 的即时响应,而现代系统(容器、沙箱、云存储网关)让这些假设越来越脆弱。真正稳定的文件操作,得从 Files 和 Path 出发,把 File 当作兼容层,而不是主力工具。










