推荐使用 golang.org/x/sys/unix.Statfs 而非 syscall.Statfs,因其统一字段、兼容多平台;Windows 应用 gopsutil/disk;注意挂载点路径、Bavail 与 Bfree 区别及 df 语义差异。

Go 里用 syscall.Statfs 获取磁盘剩余空间,不推荐直接调用
Go 标准库早已封装好跨平台的磁盘空间查询方式,syscall.Statfs 是底层系统调用,需要手动处理结构体字段、平台差异(Linux/macOS/BSD 字段名和偏移不同)、字节序,还容易因 Go 版本升级导致字段偏移错位。直接调用它就像绕过 os.Open 去写 syscall.Open —— 不是不行,但没必要,且极易出错。
真正该用的是 syscall.Statfs 的封装:标准库 golang.org/x/sys/unix(Unix 系统)或 os.Stat + os.File.SyscallStat(有限场景),但更稳妥的是第三方库 github.com/shirou/gopsutil/v3/disk,或者用标准库中已适配好的 unix.Statfs(注意不是 syscall.Statfs)。
unix.Statfs 在 Linux/macOS 上怎么安全调用
golang.org/x/sys/unix 提供了统一命名、字段对齐、版本兼容的 unix.Statfs 结构体和 unix.Statfs 函数,比原生 syscall 包可靠得多。
- 必须先
go get golang.org/x/sys/unix,不能只靠import "syscall" - 路径必须是挂载点(如
"/"、"/home"),传文件路径会返回根设备信息(Linux 下常见误解) - 结构体字段名与 POSIX 一致:
Bavail是非 root 用户可用块数,Bfree是所有用户可用块数,别混淆 - 块大小由
Frsize决定(不是Bsize),计算字节数要用stat.Bavail * uint64(stat.Frsize)
import "golang.org/x/sys/unix"
<p>var stat unix.Statfs_t
if err := unix.Statfs("/", &stat); err != nil {
log.Fatal(err)
}
available := stat.Bavail * uint64(stat.Frsize)
fmt.Printf("Available: %d bytes\n", available)
Windows 下没法用 unix.Statfs,怎么办
Windows 没有 statfs 系统调用,golang.org/x/sys/unix 在 Windows 构建时会编译失败。硬切平台分支写 syscall.GetDiskFreeSpaceEx 容易漏掉权限错误、符号链接解析、卷挂载点识别等问题。
立即学习“go语言免费学习笔记(深入)”;
- 不要自己拼
syscall调用 —— Windows API 参数顺序、指针类型、错误码转换极容易翻车 - 如果必须纯标准库,可用
os.Stat拿到路径所在卷,再通过filepath.VolumeName提取盘符,但无法获取准确剩余空间(Windows 不暴露裸设备统计) - 真实项目建议直接上
github.com/shirou/gopsutil/v3/disk,它内部已处理 Win32 API 封装、符号链接跳转、WMI 回退等细节,调用简单:disk.Usage("/") 返回统一结构体
为什么 df -h 和 Go 算出来的数字经常差几百 MB
不是代码错了,是语义差异:
-
df默认显示Bavail(非 root 可用),而很多人误用Bfree(root 也可用),差值通常是 5% 的保留块(ext4 默认 reserved blocks percentage) - Go 里没自动减去文件系统元数据开销(如 XFS 的 AGF/AGI 占用),
df已扣除 - 如果路径是 bind mount 或 overlayfs,
unix.Statfs返回的是底层设备信息,而df /path显示的是挂载点视图,两者可能指向不同设备 - 某些容器环境(如 Docker with overlay2)下,
Statfs返回的是宿主机 rootfs 统计,而非容器视角的限制值 —— 这时候得查/sys/fs/cgroup/memory/或/proc/1/mountinfo
真正要对齐 df 输出,得严格匹配它用的字段和挂载点解析逻辑,而不是只看一个 Statfs 调用结果。


















