归档前须先创建目标目录,用Directory.CreateDirectory确保路径存在;移动文件前用File.Open探测是否被占用,并用LastWriteTime而非CreationTime判断归档日期;限定GetFiles搜索范围避免误操作。

归档前先判断目标目录是否存在
很多脚本跑着跑着就崩在 Directory.Move 上,报错 System.IO.DirectoryNotFoundException —— 其实不是文件找不到,是归档用的年月子目录压根没创建。C# 不会自动补全路径层级,Directory.CreateDirectory 必须显式调用,哪怕目录已存在也无副作用。
- 按日期生成目标路径时,建议用
DateTime.Now.ToString("yyyy\MM"),双反斜杠防转义,直接适配 Windows 路径语义 - 别用
Path.Combine(root, "archive", dateStr)后直接Move,先Directory.CreateDirectory(targetDir) - 如果归档到网络路径(如
\\server\share),CreateDirectory仍有效,但需确保账户有写权限,否则静默失败
移动文件时避开“正在使用”导致的 IOException
批量处理日志或监控文件时,常遇到 System.IO.IOException: The process cannot access the file... because it is being used by another process。这不是代码写错了,而是源文件正被其他程序(比如记事本、Excel、甚至 VS 自己)以独占模式打开。
- 加
try/catch (IOException ex)捕获后跳过,比硬等更稳妥;重试逻辑容易让脚本卡住且不可控 - 用
File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)快速探测是否可读——能打开就大概率可移动;打不开就跳过,不抛异常 - 注意:.NET 6+ 的
File.Move默认不覆盖,若目标同名文件已存在,会直接抛IOException,得加true参数:File.Move(src, dst, true)
按修改时间而非创建时间归档更符合实际需求
用户说“按日期归档”,真正想归的往往是“昨天改过的日志”“上周生成的报表”,而不是“上周创建、今天才第一次打开的模板文件”。FileInfo.CreationTime 在复制/下载后会被重置,而 LastWriteTime 更稳定反映内容更新节点。
- 归档逻辑里统一用
fileInfo.LastWriteTime.Date计算归属日期,避免跨时区或系统时间误差干扰 - 如果要归档“过去7天”的文件,别用
DateTime.Now.AddDays(-7)算下限,改用fileInfo.LastWriteTime >= cutoffDate,防止因系统时间不准漏掉文件 - 注意 FAT32 卷的时间精度只有 2 秒,
LastWriteTime可能和实际有偏差,但对日粒度归档无影响
用 DirectoryInfo.GetFiles 配合搜索选项控制范围
直接 Directory.GetFiles(root, "*.*", SearchOption.AllDirectories) 容易扫到 bin/obj 或临时文件,不仅慢,还可能误移关键文件。归档动作必须明确边界。
- 优先用
new DirectoryInfo(root).GetFiles("*.log", SearchOption.TopDirectoryOnly),限定扩展名 + 单层扫描 - 需要递归但排除某些目录?C# 原生不支持过滤子目录,得手动遍历
GetDirectories后跳过黑名单(如"temp",".git") -
SearchOption.AllDirectories在深层嵌套路径下可能触发UnauthorizedAccessException(比如访问C:System Volume Information),建议外层加 try/catch 并记录警告,不中断主流程
事情说清了就结束。归档看似简单,真正上线后出问题的,九成卡在路径权限、文件占用、时间语义这三处。










