os.stat 仅返回文件元数据快照,非实时状态;需每次调用获取最新信息,判断存在性须用 os.isnotexist(err),目录 size() 恒为 0,符号链接需区分 lstat/stat 使用。

os.Stat 不是用来“探测”文件系统状态的轮询工具,它只是单次读取 inode 或目录项的元数据快照;想靠它做实时监控或状态跟踪,会掉进竞态、精度、性能三个坑里。
os.Stat 返回的 FileInfo 是静态快照,不是实时状态
调用 os.Stat 后拿到的 os.FileInfo 是一次系统调用的结果,内容在返回那一刻就固定了。它不会随文件后续修改自动更新,也不会反映其他进程刚写入的内容。
- 常见误用:缓存
info多次复用判断“文件是否变大”,结果漏掉中间变更 - 正确做法:需要感知变化时,每次都要重新调用
os.Stat(或改用fsnotify) - 注意:
info.ModTime()精度受文件系统限制——ext4 默认 1 秒,XFS 可到纳秒,但 Windows NTFS 通常只有 100ns 量级,且 FAT32 是 2 秒
判断文件是否存在不能只看 err != nil
os.Stat 失败不等于文件不存在,权限不足、父目录不可执行、NFS 挂载异常、悬空符号链接都可能返回非 os.ErrNotExist 的错误。
- 必须用
errors.Is(err, os.ErrNotExist)或os.IsNotExist(err)做精准判断 - 若返回
&os.PathError{Op: "stat", Err: syscall.EACCES},说明路径存在但无权限访问,不是“不存在” - 对硬链接或重解析点(Windows),
os.Stat和os.Lstat行为不同,别混用
Size() 对目录返回 0 是设计使然,不是 bug
FileInfo.Size() 在目录上返回 0 是 POSIX 兼容行为,Go 明确文档定义它为“常规文件的字节数”。你不能靠它判断目录是否为空,也不能拿它当磁盘占用。
- 要判断目录是否为空:用
os.ReadDir(path),检查返回的[]fs.DirEntry长度是否为 0 - 要统计目录真实磁盘用量:需递归遍历 + 调
entry.Info()累加Size(),但注意这不等于du -sh结果(稀疏文件、压缩卷、块对齐都会导致偏差) - 别用
Size()防 OOM:像/proc/kcore这类伪文件报告极大 size 却无法全读,应流式读取并设限
os.Stat 和 os.Lstat 的选择直接决定你能看到什么
是否跟随符号链接不是“可选项”,而是决定了你操作对象的语义边界。错用会导致逻辑绕过或权限误判。
- 想检查某路径是不是符号链接本身 → 必须用
os.Lstat,再判断fi.Mode() & os.ModeSymlink != 0 - 想获取目标文件的真实大小和修改时间 → 用
os.Stat,它会穿透所有中间链接 - 备份工具或路径校验(如防止
../etc/passwd)必须先Lstat检查类型,再按策略决定是否Stat目标 - Windows 上重解析点(junction、symlink)对
Lstat返回ModeSymlink,但Stat可能失败(取决于权限和目标可达性)
真正容易被忽略的是:FileInfo 的字段之间没有强一致性保证。比如你用 Lstat 拿到一个符号链接的 Size()(即目标路径字符串长度),再用 Stat 获取目标的 ModTime(),这两个时间戳来自两次独立系统调用,中间可能有毫秒级偏移——别拿它们做精确时序比对。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











