std::filesystem::space返回的是路径所在挂载点的文件系统空间信息,而非路径本身;传入同一挂载点下的任意有效路径(如"/home/user"或"/")结果相同,因底层调用statvfs/GetDiskFreeSpaceEx作用于文件系统实例而非目录。

用 std::filesystem::space 获取分区剩余空间时,为什么总是返回根目录信息?
因为 std::filesystem::space 接收的是路径,但它只关心该路径所在**挂载点(mount point)** 的底层文件系统,不解析符号链接、不跨挂载点跳转。传入 "/home/user/docs" 和传入 "/",只要它们在同一个挂载设备上,返回的 space_info 就完全一样。
常见误操作是遍历目录树并逐个调用 space(),结果得到大量重复数据。真正要获取“每个挂载点”的独立信息,得先枚举挂载点本身,再对每个挂载点路径调用 space()。
- Linux/macOS 下需读取
/proc/mounts(Linux)或getfsstat()(macOS),C++ 标准库不提供挂载点枚举接口 - Windows 下可用
GetLogicalDrives()+GetDiskFreeSpaceEx(),但要注意 NTFS 卷和网络驱动器的区分 -
std::filesystem::space()本身线程安全,但路径字符串需确保生命周期有效
Linux 下手动解析 /proc/mounts 提取挂载点列表
这是最轻量、无需额外依赖的方式。注意:/proc/mounts 每行格式为 device_name mount_point fs_type options dump pass,关键字段是第2列(挂载点)和第3列(文件系统类型)。过滤掉 proc、sysfs、devtmpfs 等虚拟文件系统。
std::vector<std::string> get_mount_points() {
std::vector<std::string> mounts;
std::ifstream f("/proc/mounts");
std::string line;
while (std::getline(f, line)) {
std::istringstream iss(line);
std::string dev, mp, fstype;
iss >> dev >> mp >> fstype;
if (fstype == "ext4" || fstype == "xfs" || fstype == "btrfs" || fstype == "ntfs3") {
mounts.push_back(mp);
}
}
return mounts;
}
- 不要用
system("mount | awk '{print $3}'")—— 启动 shell 开销大,且输出格式不稳定 - 某些容器环境(如 Docker)中
/proc/mounts可能被裁剪,需 fallback 到/proc/self/mountinfo(格式更复杂,含 major:minor) - 挂载点路径必须以
/开头且无尾部斜杠,否则std::filesystem::space()可能抛std::filesystem::filesystem_error
调用 std::filesystem::space() 获取各挂载点剩余空间的正确姿势
传入挂载点路径后,返回的 std::filesystem::space_info 包含 capacity、free、available。重点区别:free 是所有用户可用的空闲字节数;available 是普通用户实际可写入量(已扣除 root 保留空间,如 ext4 默认 5%)。
立即学习“C++免费学习笔记(深入)”;
auto s = std::filesystem::space("/home");
std::cout << "Available: " << s.available << " bytes
"; // ? 通常是你想显示的“剩余空间”
- 若路径不存在或不可访问(如未挂载的 NFS 目录),会抛出
std::filesystem::filesystem_error,务必 try/catch - Windows 下对 FAT32 分区调用
space()可能返回错误值(特别是 >4GB 文件),建议优先用GetDiskFreeSpaceEx() - 数值单位是字节,展示时建议按 1024 进制换算(KiB/MiB/GiB),别用 1000 进制——用户看到 “93.2 GB available” 却写不进 93 GB 文件,会立刻怀疑程序有 bug
跨平台兼容性陷阱:Windows 驱动器号 vs Unix 挂载点
Windows 没有“挂载点”概念,只有驱动器号(C:、D:),且网络驱动器(Z: 映射到 \servershare)和物理卷行为不同。std::filesystem::space("C:") 在多数编译器下能工作,但 std::filesystem::space("C:\") 更稳妥;而 std::filesystem::space("\\server\share") 可能失败,取决于 SMB 版本和权限。
- Linux/macOS 上挂载点可以是任意目录(如
/mnt/data),但 Windows 要求路径必须指向驱动器根或有效 UNC 路径 - Clang/libc++ 在 macOS 上对 APFS 快照卷支持不完整,
space()可能返回总空间为 0 —— 需检测s.capacity == 0并跳过 - 不要假设所有挂载点都可读:Docker 容器内
/proc/mounts列出的 host 路径,容器可能无权访问,space()会失败
实际最难的部分不是调用 API,而是判断“哪些路径才算一个独立的、用户关心的存储单元”。/boot、/var/log、/tmp 常被单独挂载,但用户未必需要看到它们;而 /home 和 /(根)才是关键。要不要合并逻辑卷(LVM)、是否显示只读挂载、如何处理 bind mount —— 这些决策不在 std::filesystem 能力范围内,得靠业务逻辑兜底。


















