filepath.walk是统计目录总大小最稳妥方式,只累加普通文件size(),遇权限错误返回nil继续,避免并发导致竞态,用int64累加并注意size()是逻辑大小非磁盘占用。

用 filepath.Walk 遍历目录并累加文件大小
Go 标准库没有直接统计目录总大小的函数,必须手动遍历。最常用、最稳妥的方式是用 filepath.Walk,它能正确处理符号链接、权限错误和深层嵌套路径。
关键点在于:只对普通文件(fi.Mode().IsRegular())累加 fi.Size(),跳过目录、设备文件、socket 等非数据文件。
- 遇到
syscall.EACCES或os.ErrPermission时,返回nil继续遍历(否则整个 walk 会中断) - 不要用
os.ReadDir+ 递归——它不自动处理循环软链,且错误处理更繁琐 -
filepath.Walk是深度优先,但大小统计本身不依赖顺序,无需额外排序
注意 os.FileInfo.Size() 返回的是逻辑大小,不是磁盘占用
很多用户误以为 Size() 就是磁盘实际占用空间,其实它返回的是文件“逻辑字节数”(即 ls -l 显示的第一列),不包含元数据、块对齐、稀疏文件空洞等开销。
若需真实磁盘占用(如 du -b 行为),必须调用系统命令或解析 syscall.Stat_t.Blocks * syscall.Stat_t.Blksize ——但跨平台兼容性差,Linux/macOS 的 Blocks 单位也不统一。
- 绝大多数场景(备份估算、配额检查)用
Size()已足够 - Windows 下无法通过标准 Go API 获取精确磁盘块占用,
syscall.Stat_t不稳定且易出错 - 稀疏文件(如虚拟机镜像)的
Size()可能远大于实际磁盘使用量
避免 goroutine 泄漏和并发累加竞争
有人想用 goroutine 并行 walk 提速,但这是典型误区:I/O 密集型任务并行反而降低吞吐,且极易引发竞态。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
如果硬要并发(比如扫描多个根目录),每个 filepath.Walk 必须独立运行,并用 sync.WaitGroup 或 channel 汇总结果;切勿在单次 walk 回调里起 goroutine 并发读 os.Stat。
-
filepath.Walk回调函数内起 goroutine + 写共享变量 → 必现data race - 并发数设为 1(即串行)通常是磁盘扫描最快的选择
- 若真需提速,优先考虑 SSD 缓存、预读优化,而非代码层并发
处理超大目录时的内存与精度问题
统计 TB 级目录时,int64 足够存下总字节数(最大约 9EB),但要注意:某些旧版 Go 在 32 位系统上 int 可能溢出,务必显式用 int64 累加。
另外,filepath.Walk 本身不占大量内存,但若你在回调中缓存所有文件路径(例如为了后续处理),会迅速耗尽内存。只存必要信息,或流式处理。
- 累加变量声明为
var total int64,别用int或uint64(后者无法表示负 size,虽罕见但理论上可能) - 不要把
filepath.Walk和日志打印混在一起——高频 log 输出会显著拖慢扫描速度 - 遇到挂载点(如
/proc、/sys)时,Walk可能卡住或返回奇怪错误,建议提前过滤路径前缀
实际总大小统计没多少弯路,真正容易翻车的是对 Size() 的误解、并发滥用、以及权限错误处理不当。磁盘空间这事,老老实实串行 walk,比花哨优化更可靠。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










