用 syscall.Statfs 获取 Linux/macOS 分区剩余空间需传挂载点路径,取 F_bavail×F_bsize;Windows 须用 syscall.GetDiskFreeSpaceEx 传驱动器根路径,取第二个返回值;跨平台需提取卷名或回溯挂载点,避免 shell fallback。

用 syscall.Statfs 获取 Linux/macOS 分区剩余空间
Go 标准库不直接暴露磁盘剩余空间,得靠系统调用。Linux 和 macOS 都支持 syscall.Statfs,它返回的 Statfs_t 结构里有 F_bavail(可用块数)和 F_bsize(块大小),二者相乘就是用户可用字节数。
注意:不是所有文件系统都严格遵循 POSIX 的 “available vs free” 区别,F_bavail 才是普通用户真正能写的剩余空间,F_blocks * F_bsize 是总大小,F_bfree 是 root 可用但普通用户可能被保留的空闲空间。
实操建议:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
syscall.Statfs接收挂载点路径(如"/"或"/home"),不是设备名(如"/dev/sda1") - 调用后需检查返回错误,常见
syscall.ENOENT(路径不存在)、syscall.EACCES(权限不足) - 计算时先转成
int64再乘,避免 32 位平台溢出:int64(stat.F_bavail) * int64(stat.F_bsize)
Windows 下必须用 syscall.GetDiskFreeSpaceEx
Windows 没有 statfs,得调用 Win32 API。Go 的 syscall 包封装了 GetDiskFreeSpaceEx,它直接返回三个 *uint64:总大小、可用大小(对当前用户)、空闲大小(未分配,含系统保留)。
立即学习“go语言免费学习笔记(深入)”;
关键区别:GetDiskFreeSpaceEx 的第二个参数才是你该用的“剩余可用空间”,它等价于 Linux 的 F_bavail * F_bsize,不是第三个参数(那个包含管理员保留空间)。
实操建议:
- 路径格式必须是驱动器根路径,如
"C:\\"(双反斜杠转义)或"\\?\\C:\\"(长路径前缀,防 WinAPI 截断) - 函数返回值顺序固定:
total, available, free,别搞混顺序 - Windows 下无法用
syscall.Statfs,硬调会 panic 或返回无效数据
跨平台封装时别漏掉 filepath.VolumeName
写一个统一函数判断分区剩余空间,Windows 路径需要先提取卷名(如 C:),否则 GetDiskFreeSpaceEx 会失败;Linux/macOS 则要找最近的挂载点(比如传入 /home/user/project,得向上查到 /home 或 /)。
Go 标准库提供 filepath.VolumeName 提取 Windows 卷标,但没提供自动找挂载点的函数——得自己 os.Stat + os.Lstat 往上遍历,直到 syscall.Statfs 不报错为止。
容易踩的坑:
- 直接对任意子目录调
syscall.Statfs可能成功但返回父挂载点信息(比如/proc是独立文件系统,但Statfs("/proc/cpuinfo")会失败) - Windows 下传
"C:"(无反斜杠)会被视为相对路径,GetDiskFreeSpaceEx返回 0 - 某些容器环境(如 Docker)中,
/proc/mounts不可靠,Statfs更可信
避免用 du -sh 或 df -B1 做 fallback
有人图省事起 shell 命令解析输出,这在生产环境风险高:输出格式随 locale 变(比如德语系统 df 用逗号当小数点),不同版本 df 字段顺序可能变,且启动进程开销大、不可控。
真正需要 fallback 的场景极少,仅限:你明确知道目标系统没 syscall 支持(比如极老内核或嵌入式 Go 移植),且无法改用 cgo。
如果真要用,至少做两件事:
- 固定 locale:
env := []string{"LC_ALL=C"}传给exec.Command - 用
-P(POSIX 输出)和--output=source,fstype,size,avail(GNU df)强制结构化字段,别依赖空格分割
多数时候,老老实实写好 syscall 分支更稳。跨平台代码里最常被忽略的,是 Windows 路径结尾反斜杠缺失和 Linux 挂载点自动回溯逻辑不完整。

















