statvfs()是linux下获取文件系统总空间与用户可用空间最轻量通用接口,必须用f_frsize×f_blocks算总容量、f_frsize×f_bavail算普通用户可用空间,它不返回quota配额信息。

Linux 下用 statvfs() 读取文件系统配额和容量信息
Linux 没有统一的“配额 API”,statvfs() 是最轻量、最通用的接口,能拿到挂载点的总空间、可用空间、块大小等核心指标,但不返回用户/组配额(那是 quotactl() 的事)。它返回的是文件系统级视图,不是某个路径所在目录的逻辑配额。
关键点:
-
f_bsize是 I/O 块大小,不是磁盘物理扇区;计算容量时务必用f_frsize(基本块大小),否则在 XFS 或 Btrfs 上会高估可用空间 -
f_bavail是非特权用户可用块数,比f_bfree更贴近真实使用场景 - 所有字段都是
fsblkcnt_t类型,需转为uint64_t防溢出,尤其在 >16TB 磁盘上
#include <sys>
struct statvfs buf;
if (statvfs("/home", &buf) == 0) {
uint64_t total = (uint64_t)buf.f_frsize * buf.f_blocks;
uint64_t avail = (uint64_t)buf.f_frsize * buf.f_bavail;
double usage = 100.0 * (total - avail) / total;
}</sys>
Windows 上用 GetDiskFreeSpaceEx() 获取卷空间信息
Windows 不支持 POSIX 风格的跨平台配额查询,GetDiskFreeSpaceEx() 是最直接的选择。它返回三个 LARGE_INTEGER:总空间、空闲空间、可用给当前用户的空间(考虑配额限制)。
注意:
- 该函数只对本地卷或映射网络驱动器有效,UNC 路径(如
\\server\share)会失败并返回 0 - 若启用了磁盘配额(Quota),
lpFreeBytesAvailable就是当前用户剩余配额,而非全卷空闲量 - 必须链接
kernel32.lib,且编译时定义_WIN32_WINNT≥ 0x0500
ULARGE_INTEGER total, free, avail;
if (GetDiskFreeSpaceEx(L"C:\", &total, &free, &avail)) {
double usage = 100.0 * (total.QuadPart - avail.QuadPart) / total.QuadPart;
}
如何判断是否启用磁盘配额(Linux + Windows)
配额(quota)是独立于文件系统基础容量的策略层,不能靠 statvfs 或 GetDiskFreeSpaceEx 推断。必须显式检查。
Linux:
- 查
/proc/mounts是否含usrquota或grpquota标志 - 调用
quotactl(QCMD(Q_GETQUOTA, ...))查询具体用户配额,失败则说明未启用或无权限 - 普通用户默认无法读取配额,需
sudo或 setuid helper
Windows:
- 调用
GetVolumeInformationByHandleW(),检查dwVolumeFlags是否含FILE_VOLUME_IS_COMPRESSED无关,真正要看的是FSCTL_GET_QUOTA_INFORMATION控制码是否被支持 - 更实用的方式是尝试
QueryInformationVolume()并传入FileFsQuotaInformation类型,STATUS_NOT_SUPPORTED 表示未启用
为什么 df -h 和你代码算出来的使用率不一致
常见偏差来源有三个:
-
df默认显示f_bavail(非 root 可用空间),而很多人误用f_bfree计算,导致低估使用率 - ext4/XFS 等文件系统保留 5% 空间给 root,
f_bfree包含这部分,f_bavail已剔除 —— 这是最大差异源 - 某些容器环境(如 overlay2)中,
statvfs()返回的是底层宿主机文件系统数据,而非容器视角的“可写层”限额,需额外解析/sys/fs/cgroup/或docker system df输出
真正要监控服务可用空间,别只盯着 “总容量 × 使用率”,得盯住 f_bavail × f_frsize 这个值是否低于业务水位线 —— 它才是进程实际能写进去的字节数。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











