Linux下用statvfs()读取文件系统块配额和使用率最轻量可靠,返回挂载点维度数据而非用户配额;f_blocks×f_frsize为总容量,(f_blocks−f_bfree)/f_blocks为使用率,f_bavail×f_frsize为非root用户可用空间。

Linux 下用 statvfs() 读取文件系统块配额和使用率
直接调用 statvfs() 是最轻量、最可靠的方式,它不依赖 shell 命令或外部工具,返回的是内核 VFS 层的真实统计值。注意:它给出的是「挂载点」维度的数据,不是单个文件或用户的配额(那是 quotactl() 的事)。
关键字段说明:f_blocks 是总块数,f_bfree 是空闲块数,f_bavail 是非 root 用户可用块数(考虑了保留块),f_frsize 是块大小(不是 f_bsize,后者可能被内核对齐过)。
实操建议:
- 传入路径必须是**已挂载目录的绝对路径**(如
"/home"),不能是文件、软链接或未挂载路径,否则statvfs()返回 -1 并设errno = ENOENT - 计算使用率时优先用
(f_blocks - f_bfree) / (double)f_blocks,避免整数溢出;若需“用户可见使用率”,用(f_blocks - f_bavail) / (double)f_blocks更贴近df输出 -
f_frsize必须用于换算字节:总容量 =f_blocks * f_frsize,硬写成 512 或 4096 会出错(XFS/overlayfs 等可能用 64KB 块)
Windows 上用 GetDiskFreeSpaceEx() 替代方案
Windows 没有 statvfs(),等效 API 是 GetDiskFreeSpaceEx(),它返回三个 ULARGE_INTEGER:总空间、空闲空间、可用空间(含磁盘配额限制后的结果)。
常见错误现象:GetDiskFreeSpaceEx(L"C:", ...) 失败返回 FALSE —— 多半是路径末尾多了反斜杠(如 L"C:\")或权限不足(UAC 限制下访问系统卷)。
实操建议:
- 路径参数必须是**根目录格式**(
L"C:\"),不能是子目录(L"C:\Users"会失败) - 返回的
*lpFreeBytesAvailable已自动扣除配额限制(如果启用了 NTFS 配额),无需额外判断 - 不要用
GetDiskFreeSpace():它只返回簇数,且不支持 >2TB 卷,dwFreeClusters字段在大容量盘上会截断
跨平台封装要注意的兼容性坑
想写一次代码跑 Linux 和 Windows?别直接宏替换函数名。核心差异不在接口,而在语义解释:
- Linux
statvfs()的f_bavail受/proc/sys/fs/percent_reserved影响;WindowsGetDiskFreeSpaceEx()的lpFreeBytesAvailable受 NTFS 配额策略影响 —— 二者不可比,强行统一变量名会误导调用方 - Windows 不提供「总块数」概念,所以无法计算“块使用率”,只能算字节级比率;Linux 若用
f_bsize计算字节容量,结果可能和df -B1不一致(因f_bsize是 I/O 优化块大小,非逻辑块大小) - 容器环境(Docker/K8s)中,
statvfs()返回的是宿主机文件系统数据,不是容器层 overlay 的实际可用空间 —— 此时得查/sys/fs/cgroup/memory/或df -i /var/lib/docker,C++ 无法绕过这层抽象
为什么不用 system("df -P") 解析输出
看似简单,但生产环境极不推荐。问题不在解析难度,而在稳定性与权限:
-
df输出格式受 locale 影响:LC_NUMERIC=de_DE下数字带逗号,df -P也救不了(POSIX 标准只要求字段顺序,不保证分隔符) - 容器或 chroot 环境里
df可能根本不存在,或 PATH 被裁剪,system()返回 127 而不是有意义的错误码 - 频繁调用
system()创建进程开销大,且无法捕获 stderr(比如磁盘 I/O 错误时df报 “Input/output error”,但 stdout 仍是旧数据) - 若程序以 drop-all-capabilities 运行,
fork()可能被 seccomp 拦截,system()直接失败
真正难的不是拿到数字,而是确认那个数字代表什么场景下的什么含义——挂载点?配额限制?cgroup 约束?这些边界条件,API 比 shell 更诚实。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











