linux/macos 下用 stat() 的 st_blocks × 512 得文件真实物理占用字节数;windows 用 getcompressedfilesize() 获取 ntfs 压缩/稀疏文件实际分配字节;二者均按 inode/句柄统计,硬链接和 reflink 会重复计算,需去重。

用 stat() 获取文件系统块大小和实际分配块数
Linux/macOS 下,stat() 系统调用能拿到文件在磁盘上真实占用的物理块数量(st_blocks),单位是 512 字节(POSIX 标准),不是字节也不是文件系统逻辑块大小。这个值才是“真实物理占用”的最直接依据。
注意:st_blocks 是已分配的磁盘块总数(含间接块、元数据块等),但不含文件系统级预留空间(如 ext4 的 reserved blocks)或未写入的稀疏空洞——它反映的是内核实际提交到块设备的扇区级用量。
-
st_blocks * 512就是近似物理字节数,绝大多数场景下足够准确 - 不能直接用
st_size(文件逻辑大小),稀疏文件、压缩文件、加密文件都会导致它远小于物理占用 - Windows 不支持
stat()的st_blocks,需换用GetDiskFreeSpaceEx()+GetCompressedFileSize()组合估算,但精度下降
Windows 上用 GetCompressedFileSize() 处理 NTFS 压缩与稀疏
NTFS 支持透明压缩和稀疏文件,GetFileSize() 返回的是逻辑大小,而 GetCompressedFileSize() 才返回实际分配的字节数(含压缩后尺寸、非零数据块占用)。这是 Windows 下最接近“物理占用”的 API。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 对未压缩的普通文件,
GetCompressedFileSize()和GetFileSize()返回值相同 - 对压缩文件或稀疏文件,前者明显更小;但它不计入 NTFS 元数据开销(如 MFT 记录、属性列表),所以仍略低于底层块设备用量
- 必须检查返回值是否为
INVALID_FILE_SIZE,且GetLastError()是否为ERROR_INVALID_FUNCTION(说明文件不支持该查询,例如某些重解析点)
跨平台统一处理时绕不开的陷阱:硬链接、子卷、reflink
同一文件可能通过多个硬链接存在,st_blocks 或 GetCompressedFileSize() 都是按 inode / 文件句柄统计,不是按路径。若你遍历目录并累加所有文件的物理占用,会重复计算硬链接指向的同一份数据。
- Linux 下可用
st_dev+st_ino去重;Windows 下靠BY_HANDLE_FILE_INFORMATION.nFileIndexLow/High - Btrfs/ZFS 的 reflink 克隆也共享物理块,但
stat()无法区分 reflink 和普通文件,st_blocks仍只报本路径的“视图”用量 - 同一目录下不同子卷(btrfs subvolume)的文件,
st_dev不同,但物理磁盘可能是同一块 SSD——此时“分区级真实占用”需额外调用ioctl(BLKGETSIZE64)或GetDiskFreeSpaceEx()对比前后差值
别把 df 和单文件统计混为一谈
用户常误以为“文件物理占用 = 所在分区 df -B1 的已用空间变化量”,但这是错的。文件创建/删除受延迟分配、日志写入、预留块、journal 空间等影响,df 值滞后且不可预测。
- 想验证单个文件真实开销?先清空 page cache(
echo 3 > /proc/sys/vm/drop_caches),再sync,再df --output=source,used对比前后 —— 但结果仍有 ±1 个文件系统块误差 -
stat()的st_blocks是内核在分配块时即时更新的字段,比df更可靠,也更轻量 - 真正需要精确到扇区级(比如取证、存储计费)?得用
debugfs(ext4)或btrfs filesystem usage直接读取块位图,C++ 层无法安全完成
真实物理占用没有银弹方案。Linux 信 st_blocks,Windows 信 GetCompressedFileSize(),跨设备或高精度场景必须结合文件系统特性做补偿——而且永远要记得:用户看到的“文件大小”,和磁盘上实际躺平的字节,根本就不是一回事。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










