C++space_info磁盘空间信息查询
C++里查磁盘空间,别再手撕statvfs了:std::filesystem::space_info真香实测
上周帮同事调一个打包工具的崩溃问题,现象很诡异——程序在某台Windows机器上总提示“磁盘空间不足”,可资源管理器明明显示还有20GB空闲。最后发现,是代码里用GetDiskFreeSpaceEx时没区分lpFreeBytesAvailable和lpTotalNumberOfFreeBytes,把“用户可用空间”错当成了“卷总空闲空间”。这事让我重新翻了遍C++17的<filesystem>,才发现space_info这个接口,不跨平台、不封装错误、不绕弯子,三行代码就能拿到真正该关心的三个数值。
std::filesystem::space_info不是什么新概念,但它常被当成“玩具接口”忽略。很多人写完exists()和is_directory()就收工,其实它藏了个极其实用的磁盘空间查询能力。关键在于:它返回的不是某个抽象的“剩余量”,而是三个有明确语义的字段——capacity(总容量)、free(卷上所有空闲字节)、available(当前进程实际能写入的字节数)。这三个数在Linux配了quota、Windows启用了配额或启用了压缩/重复数据删除的卷上,可能彼此差出好几个GB。
怎么用?最简场景:检查某个路径所在分区是否够写一个500MB的临时文件。
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
bool has_enough_space(const fs::path& target, uintmax_t required_bytes) {
try {
auto space = fs::space(target); // 关键:传入任意路径,自动定位到其所在文件系统
return space.available >= required_bytes;
} catch (const fs::filesystem_error&) {
return false; // 路径不可访问、无权限、跨网络挂载失败等
}
}
// 调用示例
if (!has_enough_space("/tmp/cache", 500 * 1024 * 1024)) {
std::cerr << "磁盘空间紧张,跳过缓存生成\n";
}
注意这里传的是target路径,不是设备名。fs::space()会自动解析路径归属的挂载点(Linux/macOS)或驱动器根目录(Windows),你不用自己realpath()再截字符串——这点比手动调statvfs或GetDiskFreeSpaceEx省心太多。
但得说句实在话:space_info不是万能钥匙。它查的是“当前用户+当前进程上下文下的可用空间”,如果程序以管理员身份运行,而目标路径在受限用户目录下(比如C:\Users\Alice\AppData\Local),available反映的就是Alice的配额余量,不是系统总空闲。这反而是优点:它告诉你“你现在真能写多少”,而不是“理论上硬盘还剩多少”。
另一个容易踩的坑是单位。space_info里三个字段全是uintmax_t,单位是字节。别手痒去除1024再除1024——直接用std::format或手动换算更可控:
auto s = fs::space("/home");
std::cout << fmt::format("可用:{:.1f} GB", s.available / (1024.0 * 1024 * 1024));
如果你需要监控多个路径(比如日志目录、上传目录、缓存目录),别反复调fs::space()。实测在某些NAS挂载点上,每次调用都有毫秒级延迟。更稳的做法是缓存结果,加个30秒有效期:
struct SpaceCache {
mutable std::map<std::string, std::pair<fs::space_info, std::time_t>> cache;
mutable std::shared_mutex mtx;
fs::space_info get(const fs::path& p) const {
auto key = p.root_path().string();
std::shared_lock lock(mtx);
auto it = cache.find(key);
if (it != cache.end() && std::time(nullptr) - it->second.second < 30) {
return it->second.first;
}
lock.unlock();
std::unique_lock wlock(mtx);
auto& entry = cache[key];
entry.first = fs::space(p);
entry.second = std::time(nullptr);
return entry.first;
}
};
最后提醒一个硬限制:fs::space()在C++17中是标准行为,但MSVC 19.26(VS 2019 16.6)之前、GCC 8.1之前、Clang 7.0之前均不完全支持。如果你还在维护老编译器环境,别硬切——宁可用条件编译兜底,也别让space_info变成程序启动时的第一个异常源。
回到开头那个打包工具的问题。改用fs::space()后,我们终于能准确判断:当available < required时,是真没空间了;而free > required && available < required,则说明是权限或配额卡住了——这时该提示用户“请检查磁盘配额设置”,而不是傻乎乎地报“磁盘已满”。
查磁盘空间这件事,从来就不是为了炫技。它关乎用户体验是否平滑,关乎后台任务会不会静默失败,更关乎运维排查时少花两小时。space_info不性感,不复杂,但它把一件琐碎又关键的事,干得干净利落。下次再看到磁盘告警,先别急着打开终端敲df -h——你的C++代码,本就可以自己回答这个问题。


还没有评论,来说两句吧...