在编写系统监控、文件备份或资源调度类程序时,C++开发者往往要同时掌握两件事:一是机器上所有存储卷挂到了哪个目录,二是每块卷还剩多少空间可写。不同操作系统的接口差异很大,如果只在某一种环境调通,换平台就可能拿到空数据或触发权限异常。因此理解底层机制和可选封装库,是写出稳定工具的前提。

Linux环境下读取挂载点与剩余空间的原生方式
在Linux系统中,所有已挂载的文件系统都会记录在虚拟文件/proc/mounts里。每一行描述一个挂载实例,字段依次是设备名、挂载点、文件系统类型以及挂载参数。我们可以通过标准文件流打开这个文件,按行解析,提取第二个字段作为挂载路径。需要注意的是,有些挂载点属于内存盘或特殊文件系统,比如tmpfs、proc,它们虽然出现在列表里,但并不一定代表真实的物理硬盘分区,实战中通常要结合文件系统类型做一层过滤。
拿到挂载点目录之后,剩余空间信息可以通过statvfs系统调用获取。该函数填充一个struct statvfs结构,其中的f_bsize表示块大小,f_bfree是未使用的块数量,f_blocks是总块数。用f_bfree乘以f_bsize就能得到自由字节数。下面示例展示如何扫描/proc/mounts并计算某个挂载点的可用空间:
#include <fstream>
#include <string>
#include <vector>
#include <sys/statvfs.h>
#include <iostream>
struct MountInfo {
std::string device;
std::string mount_point;
std::string fs_type;
};
std::vector<MountInfo> read_mounts() {
std::vector<MountInfo> result;
std::ifstream file("/proc/mounts");
std::string line;
while (std::getline(file, line)) {
// 简单按空格切分,真实场景建议用更严谨的解析
std::istringstream iss(line);
MountInfo info;
iss >> info.device >> info.mount_point >> info.fs_type;
result.push_back(info);
}
return result;
}
long long get_free_bytes(const std::string& path) {
struct statvfs buf;
if (statvfs(path.c_str(), &buf) != 0) {
return -1;
}
return (long long)buf.f_bfree * (long long)buf.f_bsize;
}
int main() {
auto mounts = read_mounts();
for (auto& m : mounts) {
long long free = get_free_bytes(m.mount_point);
std::cout << m.mount_point << " free:" << free << std::endl;
}
return 0;
}
这种原生做法的优点是不依赖任何第三方库,只要系统提供procfs和POSIX接口就能编译运行。缺点在于解析/proc/mounts需要自己处理转义字符,例如挂载点路径中的空格会被写成 40,直接按空格切分就会出错。此外statvfs对某些特殊挂载可能返回零值,需要调用方判断有效性。
为了更健壮,有些项目会改读/etc/mtab或者利用mount命令输出,但原理类似。在容器环境里,/proc/mounts看到的是容器视角,若想获取宿主机真实磁盘,还需额外权限。因此原生方案适合对依赖敏感、运行环境可控的后台服务。
Windows平台使用API枚举盘符与查询空间
Windows没有统一的挂载表文件,取而代之的是盘符概念和挂载点卷(mounted volume)。最基础的枚举方式是调用GetLogicalDriveStringsW,它返回一串以双空字符结尾的盘符字符串,比如C:、D:。遍历这个缓冲区就能拿到所有逻辑驱动器。随后对每个盘符调用GetDiskFreeSpaceExW,可以分别得到用户可用字节、总空闲字节和总字节数,这个函数会自动处理配额限制,比老的GetDiskFreeSpace更可靠。
如果程序需要支持NTFS的目录挂载点(即把卷挂到某个文件夹而非盘符),则要使用FindFirstVolumeMountPointW等卷管理API,逻辑明显复杂。多数桌面工具只关心盘符级空间,因此下面代码演示了最常见的盘符枚举与空间获取:
#include <windows.h>
#include <iostream>
int main() {
WCHAR buf[256];
DWORD len = GetLogicalDriveStringsW(255, buf);
WCHAR* drive = buf;
while (*drive) {
ULARGE_INTEGER freeBytes, totalBytes, totalFree;
if (GetDiskFreeSpaceExW(drive, &freeBytes, &totalBytes, &totalFree)) {
std::wcout << drive << L" free:" << freeBytes.QuadPart << std::endl;
}
drive += wcslen(drive) + 1;
}
return 0;
}
上述代码使用宽字符接口,能正确处理中文路径。需要注意GetLogicalDriveStringsW返回的字符串末尾带反斜杠,直接传给目录遍历函数通常没问题,但若拼接其他路径要防止出现双斜杠。Windows API错误码可通过GetLastError区分权限不足与设备未就绪,比如可移动磁盘被拔出时会返回ERROR_NOT_READY。
相比Linux,Windows原生接口更偏向COM和Win32两套体系,如果未来要拿卷GUID或挂载目录,需要引入FindVolumeMountPoint相关调用,代码量会上升。很多团队为了统一跨平台逻辑,会选择封装一层抽象,把两种系统差异隐藏在内部实现后。
使用C++标准库与Boost简化空间统计实战
C++17在<filesystem>中引入了std::filesystem::space函数,它接收一个路径,返回struct space_info,包含capacity、free和available三个字段。available代表普通用户可用的空间,通常比free略小,因为系统会保留一部分给管理员。这个接口在Linux下调statvfs,在Windows下调GetDiskFreeSpaceEx,开发者无需写条件编译。但要注意,标准库并不提供枚举挂载点的能力,只能对已知路径查询,因此挂载点列表仍需平台相关代码补充。
Boost.FileSystem在早期C++11项目中常被使用,其boost::filesystem::space接口与标准库几乎一致,且支持老编译器。若项目已依赖Boost,可顺带用boost::process或系统调用封装去读挂载信息。下面展示标准库查询空间的简洁写法:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path p = "/";
std::error_code ec;
auto info = fs::space(p, ec);
if (!ec) {
std::cout << "capacity:" << info.capacity
<< " free:" << info.free << std::endl;
}
return 0;
}
在实战架构里,推荐把平台相关的挂载点扫描单独放在一个源文件中,通过抽象接口暴露vector<MountInfo>,而空间统计统一走std::filesystem::space。这样单元测试时可以用伪挂载列表验证业务逻辑,不必真的依赖操作系统。若需要图形界面展示,还可以把剩余空间换算成GB并标记告警阈值。
最后提醒,无论用哪套方案,都要处理权限错误和异步卸载。比如U盘在查询过程中被拔出,Linux的statvfs会返回错误,Windows会报设备未就绪,程序应捕获异常或错误码,避免崩溃。把挂载点与空间信息封装成带时间戳的缓存结构,也能减少频繁系统调用带来的开销。
C++mount_pointdisk_space修改时间:2026-08-15 02:48:34