windows下用getdiskfreespaceex获取磁盘剩余空间最可靠,需传入"c:"格式路径、检查返回值、用ularge_integer接收;linux/macos应使用statvfs并乘f_frsize计算字节数。

Windows 下用 GetDiskFreeSpaceEx 获取驱动器空间信息
直接调用 Windows API 是最轻量、最可靠的方式,不需要额外依赖或权限提升。注意该函数要求传入的是带冒号和反斜杠的完整根路径(如 "C:\"),不是单个字母 "C:" —— 后者在某些系统配置下可能返回错误结果或触发访问拒绝。
常见错误现象:传入 "C:" 时返回 FALSE 或 lpFreeBytesAvailable 为 0;未检查返回值导致程序用到未初始化的数值;误把 lpTotalNumberOfBytes 当作可用空间。
- 必须以字符串形式传入
"X:\ "(末尾双反斜杠是必需的,单反斜杠会被转义) - 三个输出参数都必须是非空指针,哪怕你只关心剩余空间,也要传入合法地址
- 返回值为
FALSE表示失败,此时应检查 GetLastError(),常见原因是路径不存在或权限不足(如访问网络驱动器失败)
ULARGE_INTEGER free, total, totalFree;
if (GetDiskFreeSpaceEx(L"C:\", &free, &total, &totalFree)) {
std::wcout <h3>Linux/macOS 下用 <code>statvfs</code> 替代方案</h3><p>POSIX 系统没有“驱动器”概念,而是按挂载点(mount point)统计,比如 <code>/</code>、<code>/home</code>、<code>/mnt/data</code>。你需要先确认目标路径是否为独立文件系统根目录,否则得到的是上级挂载点的数据。</p><p>容易踩的坑:传入 <code>/dev/sda1</code> 这类设备路径会失败(<code>statvfs</code> 只接受挂载路径);忽略 <code>f_frsize</code> 直接用 <code>f_bsize</code> 计算会导致容量偏差;未处理符号链接导致实际查到的是其他挂载点。</p>
- 使用
statvfs("/path", &buf),其中/path必须是已挂载的目录(如"/"或"/mnt/mydisk") - 总容量 =
buf.f_frsize * buf.f_blocks,剩余空间 =buf.f_frsize * buf.f_bavail(注意是f_bavail,不是f_bfree,后者不含 root 预留空间) - 跨平台代码中建议封装判断:Windows 走
GetDiskFreeSpaceEx,其他系统走statvfs
C++ 跨平台封装时的类型与单位陷阱
两个 API 返回的都是字节数,但底层类型不同:ULARGE_INTEGER 是结构体,statvfs::f_blocks 是 fsblkcnt_t(通常是 unsigned long long)。直接用 int64_t 接收可能截断,尤其在 32 位编译环境下。
更隐蔽的问题是单位换算:用户常期望显示 GB,但严格来说 1 GB = 1000³ 字节(SI 单位),而系统报告的是 1024³(GiB)。混用会导致数值差约 7% —— 比如显示 “100 GB” 实际只有 93 GiB。
- 推荐统一用
uint64_t存储原始字节数,避免有符号溢出 - 显示时明确标注单位:用
"GiB"表示 1024 进制,"GB"表示 1000 进制,不要默认四舍五入到整数,保留一位小数更可信 - Windows 下
GetDiskFreeSpaceEx的lpFreeBytesAvailable返回的是当前用户可用空间(考虑配额),而lpTotalNumberOfBytes是物理总容量 —— 这点和statvfs的f_bavail/f_blocks语义一致
不推荐用 std::filesystem::space 的真实原因
C++17 引入的 std::filesystem::space 看起来最简洁,但它在 Windows 上底层仍调用 GetDiskFreeSpaceEx,在 Linux 上调用 statvfs,看似跨平台,实则隐藏了关键限制:它无法指定驱动器字母(Windows)或挂载点(Linux),只能传入某个路径,然后向上追溯到最近的挂载根。这意味着 std::filesystem::space("C:\temp") 和 std::filesystem::space("C:\") 结果相同,但 std::filesystem::space("D:\") 才真正对应 D 盘。
问题在于:如果传入的是软链接、子目录或未挂载路径,行为不可控;且无法获取总容量以外的元数据(如文件系统类型、块大小)。
- 仅当你的目标路径确定位于独立挂载点(如
"C:\"或"/mnt/ssd")时才可安全使用 - 不要用它探测
"Z:"这类可能未连接的网络驱动器 —— 它会阻塞数秒甚至超时,而原生 API 可通过SetErrorMode或信号处理控制响应 - 调试时发现
space返回异常值,优先检查路径是否存在、是否可访问,而不是怀疑函数本身
驱动器空间查询看着简单,但路径格式、挂载语义、单位定义、错误传播这四点,任一出错都会让结果偏离预期。别图省事跳过错误检查,也别假设所有系统对“C:”的理解一致。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











