GetDiskFreeSpace是Windows下获取簇大小最可靠方式,需传入驱动器根路径如"C:\",返回每簇扇区数和每扇区字节数以计算簇大小;Linux/macOS应使用statvfs获取f_frsize作为等效值。

Windows 下用 GetDiskFreeSpace 获取簇大小和扇区信息
直接调用系统 API 是最可靠的方式,GetDiskFreeSpace 能一次性拿到每簇字节数、每扇区字节数、每簇扇区数等关键参数。它不依赖文件路径,只关心驱动器根路径(比如 "C:\"),所以哪怕目标文件在深层目录,你也得先提取其所在卷的根路径。
常见错误是传入完整文件路径(如 "C:\data\file.txt")导致失败——这个函数根本不接受文件路径,只认驱动器根目录加反斜杠的格式。
- 必须确保路径以
"X:\"形式传入,末尾双反斜杠不能少 - 返回值为 0 表示失败,此时应调用
GetLastError()查具体原因(比如权限不足或路径无效) - 注意参数顺序:
lpSectorsPerCluster、lpBytesPerSector、lpNumberOfFreeClusters、lpTotalNumberOfClusters,别把扇区数和簇大小搞混
DWORD sectorsPerCluster, bytesPerSector, freeClusters, totalClusters;
BOOL ok = GetDiskFreeSpace(L"C:\", §orsPerCluster, &bytesPerSector,
&freeClusters, &totalClusters);
if (!ok) { /* 处理错误 */ }
// 簇大小 = sectorsPerCluster * bytesPerSector
Linux/macOS 下用 statfs 或 statvfs 查块大小
POSIX 系统没有“簇”概念,但有逻辑块大小(f_bsize)和基础块大小(f_frsize),后者更接近 Windows 的“每簇字节数”。statvfs 是推荐接口,比老的 statfs 更具可移植性。
容易踩的坑是误以为 f_bsize 就是磁盘分配单位——其实它只是 I/O 优化建议值;真正决定文件存储粒度的是 f_frsize(fundamental filesystem block size)。很多工具(如 df -B1)默认显示的也是这个值。
立即学习“C++免费学习笔记(深入)”;
- 传入任意路径即可(支持文件或目录),函数自动定位到其所在挂载点
- 如果路径跨挂载点(比如符号链接指向另一分区),
statvfs仍返回目标路径所在设备的信息 - 注意:
f_frsize可能等于f_bsize,也可能小得多(如 ext4 常见 4096 vs 512)
struct statvfs buf;
if (statvfs("/path/to/file", &buf) == 0) {
size_t cluster_size = buf.f_frsize; // 实际分配单位
}
为什么不能用 std::filesystem::file_size 或 stat 查簇大小
std::filesystem::file_size 和 C 的 stat 系列函数只返回文件逻辑大小,完全不涉及底层存储布局。它们读的是 inode/mft 中记录的字节数,和磁盘上实际占了多少簇毫无关系。
典型错误现象:一个 1 字节的文件,file_size 返回 1,但磁盘上可能占了 4096 字节(一整个簇)。想算出“真实占用”,你得先知道簇大小,再向上取整——而这一步,必须靠上面两个系统级 API 完成。
-
stat的st_blksize是 I/O 缓冲建议值,不是分配单位 -
st_blocks * 512是 POSIX 标准块数(512 字节/块),但实际分配仍按f_frsize对齐 - C++20 的
std::filesystem没有扩展接口获取存储对齐信息,别指望它
跨平台封装时要注意的兼容性细节
Windows 的簇大小是卷级属性,Linux/macOS 的 f_frsize 是文件系统级属性,两者语义基本对等,但行为边界不同:NTFS 卷可以有多个簇大小(压缩/稀疏文件例外),而 ext4/XFS 等通常全卷统一。
最常被忽略的一点:SSD 或某些虚拟化环境(如 WSL2)下,f_frsize 可能返回 4096,但底层 NAND 页大小是 8KB 或更大——用户空间看到的“簇”只是文件系统抽象层的单位,不是物理 NAND 页或 RAID 条带大小。
- 不要试图用这些值推算 SSD 寿命或写放大,那需要 ioctl 或 vendor-specific 工具
- 在容器或网络文件系统(NFS/SMB)上,
statvfs返回的是服务器端文件系统的f_frsize,客户端无法感知本地磁盘特性 - Windows 上若文件在 ReFS 卷,
GetDiskFreeSpace依然可用,但 ReFS 内部使用变长分配单元,API 返回的仍是对外暴露的固定簇大小



















