删除文件前必须先用File.Exists判断是否存在,再调用File.Delete;注意TOCTOU问题,权限不足抛UnauthorizedAccessException,文件被占用抛IOException;File.Delete与FileInfo.Delete行为一致,无异步版本。

删除文件前必须检查文件是否存在
直接调用 File.Delete 删除一个不存在的文件会抛出 FileNotFoundException,这不是异常处理的“优雅场景”,而是可预防的逻辑错误。尤其在多线程或异步操作中,文件可能被其他进程抢先删除。
正确做法是先用 File.Exists 判断,再执行删除:
if (File.Exists(filePath))
{
File.Delete(filePath);
}
注意:这个判断+删除不是原子操作,仍存在微小时间窗口(TOCTOU 问题),但对绝大多数业务场景已足够安全;如需强一致性,应配合文件锁或重试机制。
权限不足和文件被占用是最常见的两个报错原因
运行时抛出 UnauthorizedAccessException 表明当前进程没有写权限(例如目标在系统目录、UAC 限制下未提升权限);抛出 IOException 往往是因为文件正被其他进程打开(如 Excel 正在编辑该 .xlsx 文件、记事本未关闭、防病毒软件正在扫描)。
应对建议:
- 确保路径指向的是普通文件而非目录(
File.Delete不接受目录,否则抛IOException) - 用
try/catch捕获具体异常类型,而不是泛 catchException - 调试时可用
ProcessExplorer或命令行handle.exe查看哪个进程持有了该文件句柄 - 若需强制释放,通常需先关闭持有句柄的应用,.NET 本身不提供“强行踢出”API
使用 File.Delete 还是 FileInfo.Delete?
二者行为完全一致,底层都调用同一 Win32 API;区别仅在于使用风格:File.Delete 是静态方法,适合单次操作;FileInfo.Delete 需实例化,适合反复操作同一文件(例如后续还要读取属性、移动等)。
示例对比:
// 简单删除,推荐用静态方法
File.Delete(@"C:\temp\data.txt");
// 若还需获取长度、创建时间等,用 FileInfo 更自然
var fi = new FileInfo(@"C:\temp\data.txt");
if (fi.Exists)
{
Console.WriteLine($"Size: {fi.Length}");
fi.Delete(); // 调用实例方法
}
性能上无差异,但频繁 new FileInfo 会产生额外对象分配,纯删除场景无需绕路。
异步删除并不可行,别被名字误导
.NET 中没有 File.DeleteAsync,所有 IO 删除都是同步阻塞的。试图用 Task.Run(() => File.Delete(...)) 包裹只是把同步操作扔到线程池,并不能真正“异步”——它不减少 I/O 等待时间,反而增加调度开销和异常捕获复杂度。
真正需要非阻塞时,应考虑:
- 将删除操作放入后台服务或计划任务,避免阻塞 UI 或请求线程
- 批量删除时加限流(如每次最多删 10 个,间隔 50ms),防止磁盘队列打满
- 日志类场景可改用“标记删除 + 定期清理”,避免实时 IO 压力
Windows 文件删除本身很快,除非是网络驱动器或磁盘严重负载,否则不必为单次 Delete 做异步封装。


















