GetDiskFreeSpaceEx仅返回卷级空闲空间,无法获取单个文件物理占用;应使用GetFileInformationByHandle读取nAllocationSize(Windows)或stat的st_blocks×512(Linux/macOS)来获知实际磁盘字节数。

Windows 下用 GetDiskFreeSpaceEx 只能查空闲空间,不是文件占用
很多人以为调用 GetDiskFreeSpaceEx 就能反推单个文件占了多少物理字节,其实不行——它返回的是整个卷的空闲/总空间,和文件无关。真正要查“这个文件实际占多少磁盘字节”,得看它在磁盘上分配了多少簇(cluster),也就是它的 AllocationSize。
-
AllocationSize是文件系统为该文件预留的最小存储单位(通常是簇大小的整数倍),可能远大于FileSize - 例如一个 1 字节的文件,在 4KB 簇的 NTFS 分区上,
AllocationSize就是 4096 - 必须用
GetFileInformationByHandle获取BY_HANDLE_FILE_INFORMATION结构体,其中nFileSizeHigh/nFileSizeLow是逻辑大小,nAllocationSizeHigh/nAllocationSizeLow才是物理占用
Linux/macOS 用 stat 查 st_blocks × 512 才是真实磁盘占用
POSIX 系统里没有“分配大小”字段,但 stat 结构体里的 st_blocks 记录了文件实际占用的 512 字节块数(注意:不是扇区,是 POSIX 定义的“block”,固定为 512 字节)。直接乘出来就是物理字节数。
-
st_blocks包含所有数据块 + 元数据块(如间接块),但不含目录项本身开销 - 稀疏文件(
lseek跳过写入)会导致st_blocks明显小于st_size / 512 - 别用
du -b,它默认按逻辑大小输出;要用du --apparent-size对比才看得出差异 - 示例:
struct stat sb; stat("foo.txt", &sb); off_t physical_bytes = sb.st_blocks * 512;
C++ 跨平台封装要注意 st_blocks 和 nAllocationSize 的语义不等价
表面上都是“磁盘占用”,但 Windows 的 nAllocationSize 和 Linux 的 st_blocks × 512 并不完全对等:前者是分配单元向上取整的结果,后者是实际写入的块数(含间接块),且受文件系统实现影响。
- NTFS 压缩或加密文件:
nAllocationSize仍反映未压缩前的分配量,而st_blocks在 Linux 上对压缩文件无意义(ext4 不原生支持压缩) - 硬链接:各链接共享同一组数据块,
st_blocks不重复计算;但 Windows 没有硬链接的AllocationSize共享概念(每个句柄独立) - 不要试图把两者统一成“真实物理字节数”——它们只是各自平台下最接近的可用指标
- 跨平台工具中建议分别实现,加注释说明来源,避免混用
容易被忽略的点:碎片、压缩、稀疏文件会让“物理占用”动态变化
同一个文件,AllocationSize 或 st_blocks 并非恒定值。文件追加写、截断、碎片整理、启用压缩后,这些值都可能改变。
立即学习“C++免费学习笔记(深入)”;
- Windows 上用
Defrag整理后,nAllocationSize可能变小(合并簇) - Linux 上用
chattr +c启用 ext4 压缩后,st_blocks会下降,但st_size不变 - 稀疏文件用
truncate扩大逻辑大小但不写数据,st_blocks不增加;而 Windows 上SetFilePointerEx+SetEndOfFile可能触发分配,nAllocationSize立即上涨 - 所以任何依赖这类值做容量预估的逻辑,都得考虑时效性——它只代表“此刻”的状态



















