std::filesystem::space 返回的是“可用空间”,即用户实际能写入的空间(available),已扣除root保留、配额等限制;free仅表示文件系统未占用块数,未必可被普通用户使用。

filesystem::space 返回的是“可用空间”还是“空闲空间”?
std::filesystem::space 返回的 space_info 结构体里有三个字段:capacity、free、available。关键区别在于:available 是普通用户**实际能写入的空间**(已扣除 root 保留空间、配额限制、ACL 等影响),而 free 是文件系统层面未被占用的块数(可能包含 root 保留区)。Linux 上常见 root 默认保留 5% 空间,此时 available 会明显小于 free;Windows 通常二者相等。
所以,要获取“用户真正还能用多少”,必须用 available,不是 free。
调用 filesystem::space 前必须检查路径是否有效
传入无效路径(如不存在的目录、无权限访问的挂载点、符号链接末尾不可达)会导致抛出 std::filesystem::filesystem_error。不能假设 space() 总是安全的。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
std::filesystem::exists(path)或std::filesystem::is_directory(path)预检,但注意:存在 ≠ 可查空间(例如挂载点被 umount 后路径仍存在) - 更可靠的做法是直接 try/catch:
space()抛出的异常code().value()在 Linux 常见EPERM(权限不足)、ENOTBLK(非块设备路径)、ENOTCONN(NFS 挂载失效) - 路径应指向**挂载点根目录**(如
"/home"、"C:/"),而非任意子目录——虽然多数实现会向上追溯到所在文件系统根,但标准不保证,且跨 bind mount 或 overlayfs 时行为不确定
注意 C++17 标准与 libc++/libstdc++ 的实际差异
Clang + libc++(macOS 默认)和 GCC + libstdc++ 对 space() 的底层调用不同:libc++ 调用 statfs(),libstdc++ 在 Linux 调用 statvfs()。二者对某些字段(尤其是 available)的计算逻辑一致,但遇到 NFS、tmpfs、FUSE 文件系统时,返回值可能因内核版本或服务器配置而异。
示例(获取 C 盘可用字节数):
try {
auto info = std::filesystem::space("C:/");
std::cout << "Available: " << info.available << " bytes
";
} catch (const std::filesystem::filesystem_error& e) {
// e.code().message() 可能是 "Permission denied" 或 "No such file or directory"
}
注意:info.available 是 uintmax_t,别用 int 接收,否则在 >2TB 的磁盘上会溢出。
Windows 下驱动器号和 UNC 路径的特殊处理
Windows 上,std::filesystem::space("D:") 和 std::filesystem::space("D:/") 行为不同:前者可能失败(EINVAL),后者才被广泛支持。UNC 路径如 "\\server\share" 理论上支持,但实际依赖 Windows API GetDiskFreeSpaceEx 是否识别该网络路径——若共享未映射为驱动器号,常返回 ERROR_NOT_SUPPORTED。
稳妥做法:
- 统一使用带尾部斜杠的格式:
"C:/"、"D:/" - 避免裸驱动器号:
"C:"不推荐 - UNC 路径优先转为映射驱动器(如 Z: → \\nas\data),再查
Z:/ - 不要依赖
std::filesystem::current_path()的返回值直接传给space()——它可能是相对路径或包含..,先std::filesystem::weakly_canonical()归一化
跨平台代码里最容易被忽略的一点:Windows 驱动器号大小写不敏感,但 space() 实现可能严格匹配大小写;Linux 下挂载点路径大小写敏感,且符号链接目标是否可访问直接影响结果——这些边界情况不会报错,但返回值可能意外为 0 或极小值。


















