linux/macos用statvfs获取磁盘空间最直接,正确公式为f_blocks f_frsize算总空间、f_bavail f_frsize算可用空间;windows须用getdiskfreespaceex,需条件编译并统一返回uint64_t。

Linux/macOS 用 statvfs 获取磁盘空间最直接
Linux 和 macOS 都支持 POSIX 的 statvfs,它比 statfs 更标准化,字段语义清晰(比如 f_frsize 是“基本块大小”,不是 f_bsize),跨这两个系统几乎不用改逻辑。
常见错误是直接用 f_blocks * f_bsize 算总空间——这会错,因为 f_bsize 是 I/O 块大小,不保证对齐;正确公式是 f_blocks * f_frsize。可用空间同理,用 f_bavail * f_frsize(注意是 bavail,不是 bfree,后者不含 root 保留空间)。
实操建议:
-
statvfs第二个参数传挂载点路径(如"/"或"/home"),不是设备名("/dev/sda1"会失败) - 检查返回值:失败时返回 -1,记得
perror("statvfs")或看errno - 不要假设
f_frsize > 0,某些老旧文件系统可能填 0,此时 fallback 到f_bsize
Windows 上必须用 GetDiskFreeSpaceEx,statvfs 不可用
Windows 没有 statvfs,强行编译会链接失败或调用空实现。别试图用 MinGW 的模拟版——它底层仍调 Windows API,且部分字段(如 f_favail)不可靠。
立即学习“C++免费学习笔记(深入)”;
正确做法是条件编译,Windows 下走 GetDiskFreeSpaceEx。它返回的是 ULARGE_INTEGER,要取 .QuadPart 成 uint64_t 才能和 Linux 版本对齐。
实操建议:
- 路径格式:传
"C:\"这种带冒号和双反斜杠的字符串,不能传"C:"或"/c/" - 函数返回 BOOL,失败时
GetLastError()才有效,别只看返回值真假 - 注意
lpFreeBytesAvailable返回的是“非特权用户可用字节数”,和 Linux 的f_bavail语义一致,别误用lpTotalNumberOfBytes当“总空间”再减去已用——它包含系统保留区,实际可用总空间应以lpTotalNumberOfBytes - lpTotalNumberOfFreeBytes推算
封装跨平台接口时,避免暴露 struct statvfs 细节
如果写一个统一的 get_disk_usage(const char* path),返回结构体里直接塞 struct statvfs 字段(比如 uint64_t total_bytes、uint64_t available_bytes)就行,别把 f_frsize、f_files 这些原始字段暴露出去。用户不需要知道底层是 f_bavail 还是 lpFreeBytesAvailable。
容易踩的坑:
- Windows 下
GetDiskFreeSpaceEx对网络路径("\\server\share")可能失败,Linux 下statvfs对 NFS 挂载点通常可用,但返回值可能滞后——得提醒调用方这是快照数据,非实时 - 路径末尾斜杠影响不大,但空字符串或
"."在 Windows 下可能解析为当前驱动器根目录,在 Linux 下会解析为当前工作目录挂载点,行为不一致,建议强制规范化(realpath或GetFullPathName) - 不要在头文件里
#ifdef _WIN32夹杂 Windows API 类型(如ULARGE_INTEGER),用uint64_t统一收口
性能与线程安全:一次调用开销小,但别在热循环里反复查
statvfs 和 GetDiskFreeSpaceEx 都是系统调用,但耗时极低(通常
所以如果你做监控程序,每秒调一次纯属浪费,10 秒一次足够;如果做安装器校验空间,查一次就行,不必反复验证。
线程安全方面:两个函数都是纯读操作,无全局状态修改,可多线程并发调用,无需加锁。
最后提一句:别用 df 或 wmic 这类命令行工具做封装——启动进程开销大、输出解析易错、权限受限(比如容器里没 df)、还引入 shell 依赖。系统调用才是正路。










