最可靠方式是直接调用 statvfs:传入真实路径(如 "/"),用 f_frsize × f_bavail 计算可用字节,返回 0 表示成功;枚举所有挂载点需解析 /proc/mounts(推荐 getmntent),并过滤虚拟文件系统。

Linux 下用 statvfs 获取挂载点剩余空间最可靠
直接调用 statvfs 是 C++(POSIX 环境)里获取单个路径挂载点容量信息的底层标准方式,比解析 /proc/mounts 或调用 df 命令更轻量、更可控,也避开了 shell 注入和解析格式变化的风险。
常见错误是传入非挂载点路径(比如 /home/user/docs),statvfs 会返回其所在文件系统的统计值,而非该路径“自身”——但文件系统本身没有“子目录级剩余空间”,所以这其实是正确行为,只是容易误解。
- 务必传入一个**实际存在的路径**(哪怕只是
"/"或"/home"),statvfs自动向上查到最近挂载点 -
f_frsize是文件系统“基本块大小”,计算可用字节时必须用它乘f_bavail,别错用f_bsize(I/O 优化块大小,不可靠) - 返回值为 0 表示成功;-1 表示失败,需检查
errno(如ENOENT路径不存在,ENOTDIR中间某段不是目录)
#include <sys/statvfs.h>
#include <iostream>
<p>void print_disk_usage(const std::string& path) {
struct statvfs buf;
if (statvfs(path.c_str(), &buf) != 0) {
std::cerr << "statvfs failed for " << path << ": " << strerror(errno) << "
";
return;
}
uint64_t total = buf.f_frsize <em> buf.f_blocks;
uint64_t free = buf.f_frsize </em> buf.f_bfree;
uint64_t avail = buf.f_frsize <em> buf.f_bavail; // 可被非 root 用户使用的空间
std::cout << path << ": " << avail / (1024</em>1024) << " MiB available
";
}
如何枚举所有挂载点(不只是根和 home)
Linux 下没有标准 C++ API 列出全部挂载点,必须读取 /proc/mounts 或 /proc/self/mounts。注意:该文件是文本格式,每行形如 /dev/sda2 / ext4 rw,relatime 0 0,第二字段即挂载点路径。
容易踩的坑是直接用 std::ifstream 逐行读,却忽略空格分隔不固定(选项字段含逗号)、挂载点路径本身可能含空格(极少见但合法),以及符号链接未展开导致重复或遗漏。
立即学习“C++免费学习笔记(深入)”;
- 优先用
getmntent()(<mntent.h></mntent.h>),它专为解析此文件设计,自动处理字段分割与转义 - 过滤
fstype字段,跳过proc、sysfs、debugfs等虚拟文件系统,否则statvfs会失败或返回无意义值 - 对每个挂载点路径调用
realpath()消除..和符号链接,避免同一文件系统被多次统计
C++17 之后可考虑 std::filesystem::space,但有严重限制
std::filesystem::space 看起来很现代,但它只接受路径,不告诉你这个路径属于哪个挂载点,也不提供挂载选项、文件系统类型等元信息;而且在 glibc 2.28+ 之前,它的实现就是简单包装 statvfs,行为一致;但在某些嵌入式或旧 libc 上可能缺失或返回硬编码假值。
更关键的是:它无法区分不同挂载点的同名路径(比如 /mnt/usb 和 /media/disk 挂的都是同一块设备),也无法跳过 tmpfs 或 cgroup v2 的伪挂载点。
- 仅适合快速检查某个已知路径的剩余空间,不做挂载点发现逻辑时可用
- 不要用它替代
statvfs + /proc/mounts组合来构建磁盘管理工具 - 调用前务必用
std::filesystem::exists()和std::filesystem::is_directory()预检,否则抛std::filesystem::filesystem_error
Windows 下得换一套逻辑:用 GetDiskFreeSpaceEx
Windows 没有“挂载点”概念,只有驱动器盘符(C:)和卷挂载点(如 C:mntolume1)。C++ 程序若需跨平台,不能复用 Linux 的 /proc 方案。
GetDiskFreeSpaceEx 是 Win32 最直接的 API,但它要求输入路径必须指向一个**已存在的目录**,且路径末尾不能是反斜杠("C:\\" 会失败),也不能是 UNC 路径(除非启用特殊权限)。
- 先用
GetLogicalDrives()获取所有启用的驱动器位掩码,再用DriveType过滤掉DRIVE_REMOVABLE或DRIVE_CDROM(按需) - 对每个有效驱动器(如
"C:\\"),调用GetDiskFreeSpaceEx;注意第三个参数lpFreeBytesAvailable返回的是“非管理员可用字节数”,和 Linux 的f_bavail对应 - 卷挂载点需用
FindFirstVolume/FindNextVolume枚举,再用GetVolumePathNamesForVolumeName获取其映射路径,步骤明显更重
跨平台封装时,别试图抽象出统一接口——Linux 的“挂载点”和 Windows 的“卷”语义差异太大,硬统一只会增加 bug 几率。按平台分治,各自用最稳的原生方案,才是实战中省时间的做法。


















