最可靠方式是直接调用 statvfs 并确保路径为挂载点根目录,使用 f_bavail × f_frsize 计算非特权用户可用空间,避免 Boost.Filesystem 抽象泄漏与跨平台语义差异。

Linux 下用 statvfs 获取挂载点剩余空间最可靠
直接调 statvfs 是 C++ 在 Linux 上获取分区剩余空间的底层标准方式,比解析 /proc/mounts 或调 df 命令更轻量、更可控。它不依赖 shell 环境,也不受 locale 或输出格式变化影响。
常见错误是传入路径未校验是否为挂载点根目录——比如传 "/home/user" 可能返回父挂载点(如 "/home")的信息,而非用户预期的物理分区数据。务必确保路径是挂载点本身(如 "/"、"/home"、"/mnt/data")。
-
statvfs返回的f_bavail是非特权用户可用块数,f_bfree是所有用户可用块数,监控场景建议用前者 - 单位是
f_frsize(非f_bsize),忽略这点会导致空间计算差几倍 - 若路径不存在或无权限访问,
statvfs返回 -1,需检查errno(常见ENOENT、EACCES)
struct statvfs buf;
if (statvfs("/home", &buf) == 0) {
uint64_t free_bytes = static_cast<uint64_t>(buf.f_bavail) * buf.f_frsize;
uint64_t total_bytes = static_cast<uint64_t>(buf.f_blocks) * buf.f_frsize;
}如何枚举所有挂载点并过滤出本地硬盘分区
不能只靠 /proc/mounts 文本解析,因为其中包含 tmpfs、cgroup、overlay 等伪文件系统。必须结合文件系统类型(statfs.f_type)或挂载选项做判断。
推荐流程:读取 /proc/mounts 行,用 statfs 获取实际类型,排除已知虚拟文件系统。关键过滤条件是跳过 rootfs、sysfs、proc、devtmpfs、debugfs、securityfs、tracefs、overlay、tmpfs(除非你明确需要 tmpfs 的“剩余空间”)。
立即学习“C++免费学习笔记(深入)”;
- 设备字段(
/proc/mounts第二列)为"none"或以"nodev"出现在挂载选项中,大概率是非块设备挂载 -
statfs的f_type值可查<linux/magic.h>,如EXT4_SUPER_MAGIC、XFS_SUPER_MAGIC、BTRFS_SUPER_MAGIC - 注意某些 LVM/LUKS 卷在
/proc/mounts中设备名可能是/dev/mapper/vg-lv,这类应保留
C++ 跨平台方案为什么不该盲目用 Boost.Filesystem
Boost.Filesystem::space() 在 Linux 下底层仍调 statvfs,看似跨平台,但 Windows 下行为差异极大:它返回的是卷(Volume)级信息,而 Linux 下路径可能跨 bind mount 或 overlay —— 同一个路径在 Windows 和 Linux 下语义不同,强行统一会掩盖挂载拓扑问题。
更严重的是,Boost 1.70 之前版本在 NFS 挂载点上调用 space() 可能卡死或返回错误值,因未正确处理 ESTALE;部分发行版的 Boost 静态链接还可能漏掉 librt 导致 statvfs 符号未定义。
- 若项目已用 Boost,至少升级到 1.75+ 并确认编译时链接
-lrt - 生产环境建议封装自己的
get_mount_space(const std::string& path),Linux 走statvfs,Windows 走GetDiskFreeSpaceEx,避免 Boost 的抽象泄漏 - 不要用
boost::filesystem::system_complete处理挂载点路径——它不解决 bind mount 的路径归一化问题
实际监控中容易被忽略的三个硬伤
很多磁盘监控程序只看 “剩余空间”,却栽在三个现实细节上:
- ext4 默认预留 5% 空间给 root,普通用户看到的
f_bavail已扣除这部分,但df -h显示的 “Avail” 也是这个值,所以无需额外处理;但若用f_bfree计算使用率,会误判为“还有 5% 空间可用” - 容器环境(Docker/Podman)中,
/proc/mounts是宿主机视角,而进程 chroot 或 mount namespace 隔离后,statvfs返回的仍是当前 namespace 下的有效挂载点信息——这点反而是优势,不用额外适配 - 某些 NAS 或 CIFS 挂载(如
//192.168.1.100/share)在statvfs中可能返回ENOSYS,此时应降级尝试statfs,或捕获异常后标记为 “unknown capacity” 而非 crash
挂载点不是路径字符串的简单拼接,它的拓扑结构、命名空间隔离、文件系统语义边界,才是决定 “剩余空间” 是否可信的根本。写一次代码容易,让结果在各种部署形态下都稳定,得抠进内核文档里看。


















