如何用 Directory.GetFiles
筛选指定日期前的文件
核心是获取文件最后写入时间(
File.GetLastWriteTime),再与目标截止时间比对。注意别误用
CreationTime或
LastAccessTime——日志/备份文件的“过期”通常按内容生成或归档时间判定,而
LastWriteTime最贴近这个语义。
实操建议:
先用DateTime cutoff = DateTime.Now.AddDays(-30)算出截止时间,避免在循环里反复调用
DateTime.Now遍历前加
try/catch捕获
UnauthorizedAccessException,权限不足时跳过而非中断整个清理 路径中含通配符(如
"*.log")可直接传给
Directory.GetFiles(path, "*.log"),比事后用
Path.GetExtension过滤更高效
删除前务必检查 File.IsReadOnly
很多日志归档工具(如 Log4Net 的
RollingFileAppender)会把旧文件设为只读。直接
File.Delete会抛
IOException:“拒绝访问”,错误信息里带
Access to the path is denied。
正确做法:
删之前先if (File.GetAttributes(filePath).HasFlag(FileAttributes.ReadOnly)) { File.SetAttributes(filePath, FileAttributes.Normal); }
不要用 File.SetAttributes(filePath, 0)清空所有属性——可能误删隐藏、系统等关键标记 若文件正被其他进程占用(如未关闭的日志流),
File.Delete仍会失败,此时应记录警告而非重试
用 Directory.EnumerateFiles
替代 GetFiles
避免内存暴涨
当目标目录下有数万个小日志文件时,
Directory.GetFiles会一次性返回完整字符串数组,容易触发 GC 压力甚至
OutOfMemoryException;而
EnumerateFiles返回
IEnumerable<string></string>,按需加载。
示例片段:
var cutoff = DateTime.Now.AddDays(-7);
foreach (var file in Directory.EnumerateFiles(logPath, "*.log"))
{
if (File.GetLastWriteTime(file) < cutoff)
{
try { File.Delete(file); }
catch { /* 记录失败文件路径 */ }
}
}注意:
EnumerateFiles不保证顺序,但清理场景无需排序;它也不支持递归子目录(除非显式传
SearchOption.AllDirectories),这点要和需求对齐。
生产环境必须加日志和 dry-run 开关
线上误删备份文件后果严重。上线前至少做到两点:
命令行或配置里留一个--dry-run参数,开启后只打印将删的文件路径,不执行
Delete每次运行都写入操作日志:删了几个文件、总大小、最早/最晚文件时间戳,方便回溯。别只依赖 Windows 事件日志——它不记录具体文件名 如果清理逻辑嵌在 Windows Service 里,记得用
ServiceBase.RequestAdditionalTime延长启动超时,避免大目录扫描时被系统误判为卡死
真正麻烦的不是代码写错,而是没想清楚“过期”的定义是否和运维预期一致——比如某备份脚本实际按文件名里的日期戳判断过期,而非写入时间。
