file.exists仅判断文件存在性,不保证可操作;需结合权限、路径合法性、toctou竞态及目标状态综合处理。

File.Exists 是判断文件是否存在的最直接方式,但它不等于“能操作”,更不等于“能复制或移动”。很多新手在调用 File.Copy 或 File.Move 前只检查 File.Exists,结果仍抛出 FileNotFoundException 或 UnauthorizedAccessException——问题不在判断逻辑,而在判断和操作之间存在竞态、权限缺失或路径误判。
File.Exists 返回 false 不一定代表文件真不存在
常见错误现象:路径看着没错,File.Exists(@"C:dataconfig.txt") 却返回 false,但用资源管理器能打开。
- 路径其实是目录(比如
C:dataconfig是个文件夹),File.Exists对目录永远返回false;该用Directory.Exists或File.GetAttributes统一判断 - 路径含非法字符(如
、<code>|、?),File.Exists直接抛ArgumentException,不是返回false;建议先用Path.GetInvalidPathChars()过滤或包裹try/catch - 网络路径(UNC)如
\servershareile.dat因超时或凭据失效被系统阻断,File.Exists返回false,但文件实际存在;此时应结合File.OpenRead尝试性打开来验证可访问性
复制前只检查 File.Exists 会导致 TOCTOU 竞态
TOCTOU(Time-of-Check to Time-of-Use)是真实风险:你刚确认文件存在,下一毫秒它就被别的进程删了,File.Copy 仍会失败。
- 如果只是“避免异常”,
File.Exists+File.Copy组合没问题;但若业务强依赖“存在即可靠”,应直接捕获FileNotFoundException并处理,而不是依赖前置检查 - 不要写
if (File.Exists(src) && !File.Exists(dst)) File.Copy(src, dst)—— 中间状态可能变化,且多一次 IO;更稳妥的是try { File.Copy(src, dst, overwrite: false); } catch (IOException ex) when (ex is FileNotFoundException || ex is DirectoryNotFoundException) { ... } -
File.Copy的第三个参数overwrite很关键:设为true可避免IOException(目标已存在),但不会覆盖只读文件,除非先清除FileAttributes.ReadOnly
File.Move 和 Directory.Move 的权限与原子性陷阱
File.Move 在同一卷内是原子重命名,跨卷则退化为“复制+删除”,失败时可能留下残缺副本。
- 跨卷移动时,
File.Move内部先调用File.Copy,成功后再删源文件;若中途失败,源文件还在,但目标可能有半成品;务必检查返回后目标是否存在且大小匹配 -
File.Move不检查目标目录是否存在,DirectoryNotFoundException会直接抛出;必须提前确保Path.GetDirectoryName(dst)存在,可用Directory.CreateDirectory安全创建 - 移动只读文件会失败,即使
File.Exists返回true;需先用File.SetAttributes(path, FileAttributes.Normal)清除只读标记 -
Directory.Move要求目标父目录存在,且不能有同名子项;它不递归合并,目标目录必须为空或根本不存在
FileInfo.Exists 比 File.Exists 多一次元数据读取
有人图省事把 FileInfo 当成 File.Exists 的替代品,但这是隐式性能开销。
-
FileInfo.Exists首次访问才触发系统调用,而File.Exists是立即执行;若你后续还要读Length或LastWriteTime,用FileInfo更划算 -
FileInfo构造函数不校验路径合法性,Exists属性访问时才抛ArgumentException;File.Exists则在调用时就校验并抛异常 - 对临时路径或高频检查场景(如轮询日志目录),坚持用
File.Exists;对单次操作但需多次读属性的场景(如备份前获取大小+时间戳),用FileInfo
真正容易被忽略的点是:判断存在性只是起点,复制或移动成败取决于权限、路径有效性、目标容器状态、以及操作系统对“同一卷”的定义。别让 File.Exists 给你一种虚假的安全感。










