statvfs() 是最轻量、最可靠的选择,无需额外依赖,系统调用级精度,避免了 df 命令解析的 locale、空格、列偏移等风险;它通过路径获取所在文件系统的总与可用空间,推荐使用 f_bavail 字段反映非 root 用户真实可用空间。

Linux 下 C++ 获取硬盘分区挂载点与剩余空间,statvfs() 是最轻量、最可靠的选择,无需额外依赖,系统调用级精度,且避开了 df 命令解析的脆弱性(如 locale、列对齐、多空格、挂载点含空格等)。
为什么不用 system("df -P") 解析输出
看似简单,实则高风险:
-
df -P输出受LC_ALL或LANG影响,中文环境可能把“Available”变成“可用”,列顺序或标题行内容不可靠 - 挂载点含空格、换行或制表符时,按空白切分字段必然崩溃(例如
/mnt/My Passport) - 不同发行版
df版本可能插入额外列(如 XFS 的“Use%”后多一列),导致字段偏移错位 - 子进程启动有开销,频繁调用(如监控程序)易成瓶颈
用 statvfs() 获取单个路径的挂载信息
statvfs() 不查“分区”,而是查“路径所在文件系统”的统计信息——这正是你真正需要的:某个挂载点(如 /home)还剩多少空间。它返回的是 struct statvfs,关键字段是:
-
f_frsize:文件系统块大小(单位字节),用于换算 -
f_blocks:总块数;f_bfree:空闲块数;f_bavail:非 root 用户可用块数(更实用) -
f_files/f_ffree:inode 总数与空闲数(可选检查)
示例代码片段:
立即学习“C++免费学习笔记(深入)”;
#include <sys/statvfs.h>
#include <iostream>
#include <string>
<p>bool get_disk_usage(const std::string& path, uint64_t& total_bytes, uint64_t& available_bytes) {
struct statvfs buf;
if (statvfs(path.c_str(), &buf) != 0) return false;
total_bytes = static_cast<uint64_t>(buf.f_frsize) <em> buf.f_blocks;
available_bytes = static_cast<uint64_t>(buf.f_frsize) </em> buf.f_bavail;
return true;
}</p><p>// 调用:get_disk_usage("/home", total, avail);
如何枚举所有挂载点(不依赖 /proc/mounts 手动解析)
C++ 标准库不提供跨平台挂载点枚举,Linux 下最稳的方式是读取 /proc/mounts,但必须严格按字段分割(用空格+制表符为分隔符,跳过注释行),且只取第 2 列(挂载点)和第 3 列(文件系统类型)——过滤掉 proc、sysfs、devtmpfs 等虚拟文件系统:
- 逐行读
/proc/mounts,std::getline()+std::istringstream按空白拆分 - 跳过以
#开头的行 - 确保至少 3 个字段,第 3 字段不是
proc、sysfs、debugfs、securityfs、devtmpfs、tmpfs(除非你真要监控/dev/shm) - 对每个有效挂载点路径调用
statvfs()
注意:/proc/mounts 是内核实时视图,比 getmntent() 更底层、无 libc 缓存干扰,且不依赖 <mntent.h></mntent.h>(某些嵌入式 libc 可能不提供)。
容易被忽略的关键细节
f_bavail 和 f_bfree 差别极大:多数场景该用 f_bavail,因为 Linux 默认保留 5% 空间给 root,f_bfree 包含这部分,而普通用户进程无法使用;f_bavail 才是真实可用值。
路径必须存在且可访问:传入 "/nonexistent" 会导致 statvfs() 失败;若不确定路径是否存在,先 access(path.c_str(), F_OK) 或 opendir() 检查。
挂载点可能嵌套(如 / 和 /boot),statvfs() 对任意子路径都返回其所在文件系统的数据——所以只要传入一个已知在目标分区上的路径即可,无需“找根挂载点”。


















