c++oding="utf-8" ?>
Linux下用statvfs获取挂载点剩余空间最可靠,直接调用系统API比解析/proc/mounts或执行df命令更稳定、无shell依赖、无竞态,且自动定位路径所在文件系统的根挂载点。

Linux 下用 statvfs 获取挂载点剩余空间最可靠
直接调用系统 API 比解析 /proc/mounts 或执行 df 命令更稳定、无 shell 依赖、无竞态。关键不是“能不能”,而是“该不该”——statvfs 返回的是真实内核视图,且支持任意路径(哪怕只是某个子目录),自动定位到其所在文件系统的根挂载点。
常见错误是传入空路径或未检查返回值:statvfs("", &buf) 必然失败;statvfs("/home/user", &buf) 却完全合法。
-
buf.f_frsize * buf.f_bavail是可用字节数(普通用户视角,已扣除 reserved blocks) - 想获取总大小用
buf.f_frsize * buf.f_blocks,但注意这包含 root 预留空间 - 若需 100% 精确的“磁盘级”剩余量(含 reserved),得用
statfs+f_bfree,但可移植性下降 - 在容器或 overlayfs 环境中,
statvfs仍有效,但返回的是上层挂载点的统计,不是底层物理盘
Windows 下必须用 GetDiskFreeSpaceEx,别碰 GetDriveType 或 WMI
GetDiskFreeSpaceEx 是唯一能原子读取「总/可用/空闲」三元组的 Win32 API,且线程安全、无 COM 初始化开销。试图用 WMI 查询 Win32_Volume 虽能拿到卷标,但性能差(数秒延迟)、权限要求高(常被 UAC 或策略拦截),纯属自找麻烦。
典型误用:传入 "C:" 却没加尾部反斜杠 → 失败;正确写法是 "C:\" 或 "C:/"(Win10+ 支持正斜杠)。
- 卷标(Volume Name)需额外调用
GetVolumeInformation,参数为同一路径,不能省略 -
GetDiskFreeSpaceEx不区分“用户可用”和“系统保留”,返回的就是管理员可见的lpFreeBytesAvailable - 若路径指向网络驱动器(如
Z:\),该函数仍工作,但可能因网络延迟超时(无超时控制,只能靠外围信号量)
跨平台封装时,std::filesystem::space 只能当备选方案
C++17 的 std::filesystem::space 看似优雅,但它在 Windows 上底层仍调用 GetDiskFreeSpaceEx,Linux 上则封装 statvfs,看似省事——实际埋了三个坑:
- 不提供卷标(Volume Label)获取能力,必须另起平台分支
- 对符号链接路径行为不一致:GCC libstdc++ 会解析到目标,MSVC 则可能报错
std::filesystem::filesystem_error - 无法区分“磁盘满”和“权限拒绝”,统一抛异常,而原生 API 都有明确的
errno/GetLastError()可查 - 某些嵌入式 libc++ 实现(如 Android NDK r21)尚未完整支持,编译期就失败
结论:仅当项目已强制要求 C++17 且只读剩余空间、不关心卷标、且不运行在受限环境时,才考虑它。
卷标获取必须分平台处理,没有通用 syscall
Linux 没有“卷标”概念,所谓卷标其实是文件系统 superblock 中的 label 字段(如 ext4 的 e2label、xfs 的 xfs_admin -l),必须调用对应工具或解析设备节点——但普通进程通常无权 open /dev/sda1。更现实的做法是读取 /etc/fstab 或 findmnt --output=SOURCE,TARGET,LABEL 输出,但后者依赖外部命令。
Windows 则简单得多:GetVolumeInformation 一次调用即可拿到 lpVolumeNameBuffer,但要注意缓冲区长度至少为 MAX_PATH+1,且路径必须是驱动器根目录("D:\"),不能是子路径("D:\data" 会失败)。
- Linux 下若坚持不用外部命令,可尝试
libblkid(来自 util-linux),但需链接-lblkid,并处理 udev 设备扫描逻辑 - macOS 对应的是
getfsstat+getattrlist查ATTR_VOL_NAME,但不在本文范围 - 所有平台下,卷标都可能为空字符串(尤其 FAT32 未设置 label 时),代码必须容忍
真正难的从来不是“怎么拿数据”,而是“拿的数据是否代表用户直觉里的‘那个盘’”——比如 /home 单独挂载时,用户问“系统盘剩余多少”,你得知道该查 / 还是 /home,这需要结合 findmnt 或 getmntent 解析挂载拓扑,而非只看路径字符串。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











