syscall.statfs 返回的 f_bavail * f_bsize 才是普通用户真实可用字节数,而非 f_bfree;需按平台分别调用 syscall.statfs(unix/macos)或 syscall.getdiskfreespaceex(windows),并注意路径规范与容器场景下的挂载点选择。

用 syscall.Statfs 获取原始磁盘统计信息
Go 标准库不直接提供跨平台的“空闲空间 MB”函数,但 syscall.Statfs(Unix/Linux/macOS)和 syscall.GetDiskFreeSpaceEx(Windows)能拿到底层数据。Linux 下最常用的是 syscall.Statfs,它返回 syscall.Statfs_t 结构体,其中 F_bavail 是非特权用户可用的空闲块数,F_bsize 是 I/O 块大小——二者相乘才是真实可用字节数。
注意:F_blocks * F_bsize 是总空间,F_bfree * F_bsize 是 root 可用空间,而 F_bavail * F_bsize 才是普通用户实际能写入的空间(已扣除 reserved blocks)。很多脚本误用 F_bfree,导致预估偏高。
-
syscall.Statfs需传入挂载点路径(如"/"或"/home"),不是设备名(如/dev/sda1) - 返回值需检查
err != nil,常见错误是路径不存在或权限不足(比如对/proc或某些容器路径调用失败) - 结构体字段在不同系统上命名略有差异(如 macOS 用
Bavail大写首字母),建议用构建标签隔离或统一用go:build unix
封装跨平台函数:Linux/macOS 和 Windows 分支处理
Go 没有内置的 disk.FreeSpace,必须手动适配。Windows 不能用 syscall.Statfs,得走 syscall.GetDiskFreeSpaceEx,它直接返回三个 *uint64(总、可用、空闲字节数),且参数是目录路径(如 "C:\\"),结尾反斜杠不能省。
一个轻量封装示例:
// Linux/macOS
func getFreeBytesUnix(path string) (uint64, error) {
var stat syscall.Statfs_t
if err := syscall.Statfs(path, &stat); err != nil {
return 0, err
}
return uint64(stat.Bavail) * uint64(stat.Bsize), nil
}
<p>// Windows
func getFreeBytesWindows(path string) (uint64, error) {
var free, total, used uint64
err := syscall.GetDiskFreeSpaceEx(syscall.StringToUTF16Ptr(path), &free, &total, &used)
if err != nil {
return 0, err
}
return free, nil
}</p>
实际使用时建议用构建标签(//go:build windows / //go:build !windows)拆分文件,避免运行时类型断言或反射开销。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
避免单位换算错误:别直接除以 1000
磁盘厂商标称容量用十进制(1 KB = 1000 B),而操作系统和 Statfs 返回的是二进制字节(1 KiB = 1024 B)。如果要做“显示为 GB”,必须明确用 1024³ 还是 1000³——监控系统通常用 1024,前端展示有时用 1000。混用会导致数值偏差约 7%。
- 推荐统一用
/ 1024 / 1024 / 1024得到 GiB(gibibyte),这是内核和df -h的默认行为 - 若需匹配
df -H(十进制),则用/ 1000 / 1000 / 1000 - 不要用
float64中间转换再转回整数,易因精度丢失导致最后一位不准;优先用整数除法 + 取余做格式化
容器或 overlayfs 场景下路径选择很关键
在 Docker/Kubernetes 环境中,"/" 可能指向容器 rootfs,其空闲空间和宿主机物理磁盘无关。如果目标是监控宿主机磁盘,必须挂载宿主机路径(如 "/host")并检测该路径;如果检测容器自身限制,则应查 "/" 或 "/app" 等挂载点。
常见陷阱:
- 容器内执行
syscall.Statfs("/")返回的是容器层(如 overlay2 的 upperdir)剩余空间,不是底层 block device - 某些发行版(如 Fedora CoreOS)默认启用
zram作为 /tmp,Statfs会返回内存伪设备容量,和磁盘无关 - 使用
filepath.Clean()规范路径,避免"//var/log/"这类重复斜杠导致Statfs返回 ENOENT
真正难的不是调用哪个函数,而是搞清你要测的到底是哪一层的“空闲”——宿主机物理盘、LVM 逻辑卷、容器 rootfs 还是某个 bind mount 目录。选错路径,结果就完全不可信。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










