最稳妥的临时文件清理方式是用 Directory.GetFiles 配合 File.Delete,显式指定 SearchOption.AllDirectories、设置正常属性、捕获异常并跳过失败项,优先清理 LocalApplicationData 和 Temp 目录,避免硬路径和系统目录。

用 Directory.GetFiles 配合 File.Delete 最稳妥
直接遍历 + 删除比手动递归更可靠,.NET 内置方法已处理路径合法性、权限、只读属性等边界情况。硬写递归容易漏掉 UnauthorizedAccessException 或跳过隐藏/系统文件。
常见错误现象:Directory.GetFiles(path, "*.tmp", SearchOption.AllDirectories) 返回空数组——其实是默认不包含子目录的隐藏/系统属性文件;或删除时报“访问被拒绝”,因为没加 FileAttributes.ReadOnly 处理。
- 必须显式传入
SearchOption.AllDirectories,否则只查当前层 - 删前先设属性:
File.SetAttributes(filePath, FileAttributes.Normal) - 加 try/catch 捕获
IOException和UnauthorizedAccessException,跳过失败项(如正在被占用的日志文件) - 避免用
Directory.Delete(path, true)清整个目录——它会删空文件夹但不区分后缀,风险太高
清理系统缓存要绕开 C:Windows 和 C:Program Files
所谓“系统垃圾缓存”在 C# 里没有统一 API 可批量清,Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) 和 Temp 才是安全目标。硬扫 C:WindowsTemp 或 SoftwareDistribution 目录大概率触发 UAC 拒绝,且可能误删系统更新临时文件导致 Windows Update 失败。
使用场景:用户级临时文件清理(如程序生成的 .cache、.log.bak)、浏览器下载缓存目录(需提前确认路径)、自己应用的日志归档目录。
- 优先用
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "YourApp\Cache") - 查
%TEMP%:Path.GetTempPath(),这里文件通常无权限问题 - 绝对不要拼接
"C:\Windows\..."硬路径——不同系统版本路径不同,且 Vista 后多数子目录受保护 - 若真要碰系统缓存(如 Windows 更新缓存),应调用
DISM /Cleanup-Image命令行并以管理员权限运行,而非用 C# 文件操作
SearchOption.AllDirectories 在深层嵌套时可能抛 PathTooLongException
当某子目录路径总长度超 260 字符(Windows 默认限制),Directory.GetFiles 会直接炸,而不是跳过。这不是你代码写错了,是 Win32 层限制。
性能影响:开启长路径支持能解燃眉之急,但需改注册表或应用清单,普通工具类不应强依赖它。
- 临时方案:用
\?前缀绕过限制,例如Directory.GetFiles(@"\?" + rootPath, "*.tmp", SearchOption.AllDirectories) - 注意
\?不支持相对路径,必须传绝对路径 - 该前缀下
..和.会被忽略,所有路径视为绝对 - 更健壮的做法是改用
Directory.EnumerateFiles(.NET 4.0+),它延迟枚举、可捕获单个路径异常而不中断整个遍历
删文件前务必确认是否正在被占用
即使文件没被锁,File.Delete 仍可能因进程刚打开未关闭句柄而失败。典型表现是删完再查 File.Exists 还返回 true,或者后续写同名文件时报“文件正由另一进程使用”。
容易踩的坑:用 Process.Start("cmd", "/c del ...") 交由 shell 处理——它不会反馈是否真删掉了,也无法捕获具体错误码。
- 删前尝试用
FileStream以FileAccess.ReadWrite和FileShare.None打开,能打开说明未被占用 - 更轻量做法:捕获
IOException,检查ex.HResult == -2147024864(即 ERROR_SHARING_VIOLATION) - 对关键缓存(如 SQLite 的
-journal文件),建议先重命名再删,降低并发冲突概率:File.Move(oldPath, oldPath + ".toDelete")
真正麻烦的从来不是怎么删,而是删之前没搞清谁在用、删之后有没有其他线程正等着那个文件。路径、权限、占用状态——三个点漏一个,脚本就变成定时炸弹。


















