filepath.walk默认不处理符号链接,遇软链易致无限循环,需用filepath.evalsymlinks预展开路径并基于inode去重防重复访问。

用 filepath.Walk 遍历目录时注意符号链接循环
直接递归遍历目录容易因软链接形成无限循环,filepath.Walk 默认不处理符号链接,但若目标目录下存在指向父级或自身的软链,手动调用 os.Readlink + os.Stat 判断会更稳妥。实际清理前建议先加一层路径规范化和重复访问检测:
- 用
filepath.EvalSymlinks提前展开路径,避免后续误判 - 维护一个
map[string]bool记录已访问的os.FileInfo.Sys().(*syscall.Stat_t).Ino(Linux)或os.FileInfo.Sys().(*syscall.Win32FileAttributeData)(Windows),跳过重复 inode - 对每个文件调用
fi.ModTime().Before(time.Now().Add(-72h))判断是否超期,别用time.Since比较,它返回的是Duration,不能直接和负时间相加
删除文件前必须检查 os.Remove 的错误类型
os.Remove 失败不等于“删不动”,常见干扰项包括权限不足、文件正被占用、路径是只读目录。不能简单忽略 err != nil:
- 用
errors.Is(err, os.ErrPermission)区分权限问题,可记录日志并跳过 - 对
err == syscall.ERROR_SHARING_VIOLATION(Windows)或err.(*os.PathError).Err == syscall.EBUSY(Linux),建议重试 1–2 次,间隔 100ms - 若
os.IsNotExist(err)成立,说明文件已被其他进程删掉,属预期行为,无需报错
定时触发选 time.Ticker 还是系统 cron?
Go 程序长期运行时用 time.Ticker 最简,但进程崩溃即中断;若需强可靠性,应交由系统级调度:
- Linux 下写个
cron条目:0 2 * * * /path/to/cleaner -dir /tmp/logs -older-than 168h - Windows 用
schtasks创建每日任务,避免 Go 进程常驻带来的内存泄漏风险 - 若坚持用
Ticker,务必加recover()捕获 panic,否则一次异常会导致整个 ticker 停摆
清理逻辑里最容易被忽略的边界:目录本身是否可删
很多人只关注文件,却忘了目录也可能符合“旧”条件。比如日志按天建目录,/logs/2024-01-01/ 里文件全清了,但空目录本身创建时间早于阈值,该不该删?
- 默认策略:只删文件,保留目录结构,除非显式传参
-prune-empty-dirs - 若启用目录清理,必须先
filepath.Walk确认子项全为空(包括隐藏文件),再调用os.Remove;直接os.RemoveAll可能误删非空目录 - 特别注意:
os.Remove对非空目录返回syscall.ENOTEMPTY(Linux)或ERROR_DIR_NOT_EMPTY(Windows),需单独判断,不能混同于权限错误
实际跑起来之后,最麻烦的往往不是逻辑,而是不同系统对“文件最后修改时间”的理解差异——NTFS 记录的是写入时间,ext4 默认是 mtime,而某些容器环境挂载卷后可能冻结了时间戳。上线前务必在目标环境实测 os.Stat 返回的 ModTime() 是否真实反映文件老化程度。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











