os.Stat 是最轻量的文件元数据获取方式,但必须检查 err 再调 Size(),否则会 panic;Size() 返回逻辑字节数而非磁盘占用,目录 Size() 恒为 0。

os.Stat 是最常用、最轻量的方式,它不打开文件、不读内容,只查元数据。但直接调用后不检查 err 就调 Size() 会 panic;误把 Size() 当磁盘占用也会在压缩文件系统上出错。
os.Stat 获取单个文件大小必须检查 err
很多人写成 fi, _ := os.Stat(path); size := fi.Size(),这是危险的。一旦路径不存在、权限不足或符号链接损坏,err 非 nil,而 fi 是 nil,后续调 Size() 直接 panic。
- 正确做法:必须显式判断
err != nil,再决定是跳过、记录还是终止 - 区分错误类型:用
os.IsNotExist(err)判断是否真不存在;用os.IsPermission(err)区分“没权限”和“路径错” - 别用
err == nil反推文件存在——os.Stat在父目录无执行权限时也失败,但文件本身可能完好
FileInfo.Size() 返回的是逻辑字节数,不是磁盘占用
Size() 的值来自文件系统的 st_size 字段,对普通文件就是你写进去的字节数。但它完全不反映实际磁盘空间消耗。
- 在 ZFS/Btrfs 压缩卷、NTFS 压缩文件上,
Size()可能远大于真实占用(比如 100MB 文件实际只占 20MB) - 稀疏文件中空洞不计入
Size(),但会影响磁盘块数 - 设备文件、管道、
/proc/kcore这类特殊文件可能返回极大值(如 128TB),但根本无法完整读取——别只靠Size()做内存分配
os.ReadDir 比 filepath.Walk 快,但 DirEntry.Info() 才真正触发 stat
如果要遍历目录下所有文件并统计总大小,os.ReadDir 比 filepath.Walk 快 2–5 倍,但它返回的是 fs.DirEntry,不是 os.FileInfo。
立即学习“go语言免费学习笔记(深入)”;
-
entry.Name()和entry.IsDir()是零开销的,不用系统调用 -
entry.Info()才会发起一次stat系统调用,拿到Size()和ModTime() - 如果只需过滤文件名或跳过目录,别急着调
entry.Info();需要大小再批量调,内核可能缓存部分结果
已打开文件优先用 *os.File.Stat() 复用句柄
如果你已经调了 os.Open 准备读文件,就别再额外调 os.Stat(path)——既多一次系统调用,又可能因路径变化导致状态不一致。
- 直接用
f.Stat(),返回的os.FileInfo和os.Stat语义一致,Size()结果相同 - 注意:
f.Stat()返回的是当前打开时刻的快照,不保证后续读取时文件没被截断或追加 - 临时文件或 NFS 上的文件,
Stat()和实际读取长度可能不一致,流式读取 + 限长更稳妥
最易被忽略的一点:目录的 Size() 恒为 0(POSIX 行为),不能用来判断是否为空;而 os.ReadDir 返回的条目数才是真实子项数量。


















