用 directory.getfiles 筛选指定日期前的文件需结合 file.getlastwritetime 与截止时间比对,优先用 enumeratefiles 避免内存溢出,删除前处理只读属性并捕获异常,生产环境必须支持 dry-run 和详细日志。

如何用 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延长启动超时,避免大目录扫描时被系统误判为卡死
真正麻烦的不是代码写错,而是没想清楚“过期”的定义是否和运维预期一致——比如某备份脚本实际按文件名里的日期戳判断过期,而非写入时间。










