std::filesystem::space返回路径所在文件系统的空间信息,而非挂载点路径;它不解析符号链接、不枚举分区、不提供设备名或挂载点位置,仅封装statvfs/GetDiskFreeSpaceEx,作用域限于路径所属挂载单元。
用
获取分区剩余空间时,为什么总是返回根目录信息?
因为
接收的是路径,但它不自动识别“挂载点”,而是向上遍历直到找到该路径所属的文件系统根(即挂载点)。如果你传入
或
,它返回的是
或
所在文件系统的空间数据——但你并不知道这个“所在文件系统”具体挂载在哪条路径上。
解决办法是先找出路径对应的挂载点,再调用
。C++20 标准库本身不提供挂载点枚举功能,必须依赖系统接口。
Linux 下读取
或调用
(需
)
macOS / BSD 下用
(需
)
Windows 下用
+
Linux 下如何用
枚举所有挂载点并匹配路径?
核心思路:遍历
,对每个挂载点用
判断目标路径是否位于其子树中(注意:不能只靠字符串前缀匹配,比如
和
会误判)。
示例关键逻辑:
立即学习
“
C++免费学习笔记(深入)
”;
C知道
CSDN推出的一款AI技术问答工具
下载
务必用
而非
可能包含 tmpfs、devtmpfs 等虚拟文件系统,按
过滤(如只留
、
、
)
某些挂载点(如
、
)无法调用
,会抛
,需捕获
返回的
和
有什么区别?
这是最容易混淆的点:
是磁盘上未分配的字节数;
是当前用户(进程有效 UID)**实际可写入**的字节数——它已扣除 root 保留块(ext 系列默认 5%)、配额限制、以及可能的 overcommit 保护。
监控磁盘告警应优先看
,否则可能误报(例如 ext4 上普通用户在只剩 5% 空间时就无法写入)
≤
,差值在 ext4 上通常就是保留块大小:
某些文件系统(如 XFS)不设保留块,此时二者相等
跨平台封装时,为什么不要试图用
推导挂载点?
只解析符号链接和相对路径,不会跨越文件系统边界。例如
是独立挂载的分区,
仍返回
,而非
—— 它不感知挂载拓扑。
真正可靠的跨平台策略是分治:
Linux:坚持用
+
macOS:用
获取数量,再分配缓冲区重调,遍历
中的
Windows:用
枚举卷 GUID,再对每个卷调用
获取挂载路径(可能是驱动器号如
,也可能是挂载点如
)
别省略权限检查和异常处理——
在容器里可能不可读,Windows 某些卷可能无访问权限,这些都会让
失败。真实场景里,一个路径对应多个挂载点(bind mount)、或挂载点嵌套(如
和
)的情况也得考虑优先级,通常取最长匹配路径。
std::filesystem::spacestd::filesystem::space"./""/home/user"//homespace/proc/mountsgetmntent()getfsstat()GetVolumeInformationByHandleW()FindFirstVolumeW()getmntent/proc/mountsstd::filesystem::equivalent/mnt/data/mnt/data2FILE* fp = setmntent("/proc/mounts", "r");
struct mntent* ent;
while ((ent = getmntent(fp)) != nullptr) {
std::filesystem::path mountpoint(ent->mnt_dir);
try {
if (std::filesystem::equivalent(target_path, mountpoint) ||
std::filesystem::is_subdirectory(target_path, mountpoint)) {
auto space_info = std::filesystem::space(mountpoint);
// space_info.capacity, .free, .available
}
} catch (...) { /* 权限不足或路径不可访问 */ }
}
endmntent(fp);
std::filesystem::is_subdirectorytarget_path.string().starts_with(...)/proc/mountsent->mnt_type"ext4""xfs""btrfs"/proc/sysspace()std::filesystem::filesystem_errorstd::filesystem::spacefreeavailablefreeavailableavailableavailablefree(capacity * 0.05)std::filesystem::canonicalstd::filesystem::canonical/homecanonical("/home/user")/home/user/homegetmntentequivalentgetfsstat(NULL, 0, MNT_NOWAIT)struct statfsf_mntonnameFindFirstVolumeWGetVolumePathNamesForVolumeNameWC:\D:\Mount\Data/proc/mountsspace()/mnt/disk1/mnt/disk1/sub