正确姿势是优先用fi.ModTime()跨平台过滤,创建时间需依系统从Sys()断言底层结构获取,Linux需statx且常不支持,避免重复stat调用。

Go 中用 os.Stat 获取文件时间戳的正确姿势
直接调 os.Stat 拿到的是 os.FileInfo,它暴露三个时间字段:ModTime()(修改时间)、CreateTime()(创建时间,Windows 有效,Linux/macOS 不保证存在)、Sys()(底层结构,需类型断言)。别想当然认为 FileInfo 有 BirthTime 或 AccessTime —— 标准库不统一提供访问权限时间或创建时间。
实操建议:
- 优先用
fi.ModTime()做过滤,跨平台最稳 - 需要创建时间?Linux 下得从
fi.Sys()断言出*syscall.Stat_t,再读Birthtime字段(但内核/文件系统未必支持);macOS 用Stat_t.Birthtimespec;Windows 用winio.FileBasicInfo.CreationTime - 别用
os.Chtimes反向推创建时间 —— 它只能设修改/访问时间,且不改创建时间
按时间范围过滤文件列表的典型写法
常见需求是“列出过去 24 小时内修改过的文件”,核心是把 time.Time 和 time.Duration 对齐。注意:Go 的 time.Now().Add(-24 * time.Hour) 返回的是 UTC 时间点,而 fi.ModTime() 默认也是本地时区(time.Local),只要时区一致就可直接比较。
示例逻辑:
立即学习“go语言免费学习笔记(深入)”;
now := time.Now()
cutoff := now.Add(-24 * time.Hour)
<p>for _, path := range paths {
fi, err := os.Stat(path)
if err != nil {
continue // 忽略权限错误、不存在等
}
if fi.ModTime().After(cutoff) {
fmt.Println(path)
}
}关键点:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 用
.After()/.Before()比较,别用Sub()算秒数再比 —— 易出精度误差 - 批量处理时,提前算好
cutoff,避免循环里反复调time.Now() - 如果路径来自
filepath.Walk,注意Walk传入的os.FileInfo是缓存的,ModTime()值可靠
Linux 下读取 birth time 的兼容性陷阱
Linux 内核 4.11+ 支持 btime,但 ext4/xfs 需挂载时开启 birthtime 特性(如 mount -o birthtime),且 glibc 2.28+ 才在 statx(2) 中暴露该字段。Go 标准库至今未封装 statx,必须手撸 syscall。
简化版判断逻辑(仅作示意,生产环境需更严谨):
if stat, ok := fi.Sys().(*syscall.Stat_t); ok {
// Linux: statx 提供 Birthtime,但 syscall.Stat_t 没直接字段
// 需用 unsafe + syscall.Syscall(SYS_statx, ...) 或用第三方库如 github.com/anatol/gostatx
}现实情况:
- 90% 的线上 Linux 服务器没启用 birthtime,
statx返回 0 或 -1 - 即使支持,Go
os.Stat仍不会填充 birth time 到FileInfo—— 你得绕过标准库自己调statx - 别在跨平台工具里默认依赖 birth time,它本质上是个“尽力而为”的元数据
性能敏感场景下避免重复 stat
遍历大目录时,每调一次 os.Stat 就是一次系统调用,开销不小。如果只需判断修改时间是否在某个窗口内,可以先用 filepath.WalkDir(Go 1.16+)配合 DirEntry 的 Info() 方法,它在某些文件系统下能复用 readdir 的部分信息。
更激进的优化:
- 用
os.ReadDir替代filepath.Walk,拿到DirEntry后,只对目标文件(如后缀匹配)调entry.Info() - 若已知文件名模式(如
*.log),先用filepath.Glob缩小范围,再批量Stat - 极端情况(如监控日志目录),考虑用 inotify 或 fanotify 监听变更,而非轮询
Stat
真正难的不是怎么读时间戳,而是搞清哪个时间戳在什么系统上真的存在、是否被篡改过、以及你的业务是否真的需要它 —— 大多数时候,ModTime 就够了。

















