linux/macos用stat命令查真实物理占用:st_blocks×512字节(非st_blksize),windows用getfileinformationbyhandleex获取allocationsize;稀疏文件会导致物理占用远小于逻辑大小。

Linux/macOS 下用 stat 命令看真实物理占用(非文件大小)
文件系统里,ls -l 显示的是逻辑大小(st_size),但磁盘实际占多少块,得看它真正分配了多少个数据块。这取决于文件系统类型、块大小、稀疏程度等。
直接用系统 stat 命令最准,不用自己解析结构体:
-
stat -c "%b %B %s %n" /path/to/file(Linux):输出“分配块数 块字节数 逻辑大小 文件名” -
stat -f "%b %k %z %N" /path/to/file(macOS):对应字段是“分配块数 块字节数 逻辑大小”
真实物理字节数 = st_blocks × st_blksize(注意:st_blocks 单位是 512 字节,不是文件系统块!)。所以别直接乘 st_blksize,先确认 st_blocks 的单位——POSIX 规定它恒为 512 字节块数,哪怕 st_blksize 是 4096。
C++ 中用 stat() 获取 st_blocks 和 st_blksize
别用 fstatat() 或 statx() 来绕——除非你明确需要纳秒时间戳或扩展属性。对物理占用,stat() 足够且最便携。
关键点:
-
st_blocks是 512 字节块数,不是文件系统块数;计算物理字节数必须用st_blocks * 512,而不是st_blocks * st_blksize -
st_blksize是建议的 I/O 块大小,和实际占用无关;它只影响读写效率,不决定磁盘使用量 - 某些文件系统(如 ext4 启用
big_writes或 XFS)可能让st_blocks小于ceil(st_size / 512),这是稀疏文件的正常表现
示例片段:
#include <sys>
struct stat sb;
if (stat("/tmp/test", &sb) == 0) {
off_t physical_bytes = sb.st_blocks * 512;
printf("physical: %ld bytes\n", (long)physical_bytes);
}
</sys>
Windows 上没有直接等价的 st_blocks,得用 GetCompressedFileSize() 或 GetFileInformationByHandleEx()
Windows 没有 POSIX 风格的 st_blocks 字段,GetFileSize() 返回的只是逻辑大小。要拿真实占用,得走 Win32 API:
-
GetCompressedFileSize():仅对启用了压缩/去重的文件有效,返回压缩后大小,不是物理扇区占用 - 更可靠的是
GetFileInformationByHandleEx(hFile, FileStandardInfo, &info, sizeof(info)),其中info.AllocationSize是已分配字节数(按簇对齐) - 注意:必须用
CreateFile()打开句柄,不能传路径字符串;且需FILE_FLAG_BACKUP_SEMANTICS才能打开目录
常见坑:AllocationSize 是簇(cluster)粒度,不是扇区。一个簇 = 若干扇区(通常 4KB),所以它比真实扇区占用略大,但已是 Windows 下最接近“物理占用”的值。
稀疏文件会让 st_blocks * 512 远小于 st_size,这不是 bug
比如用 truncate -s 1G empty.img 创建的空镜像文件,st_size 是 1GB,但 st_blocks 可能是 0 或极小值——因为没写入实际数据,文件系统没分配数据块。
判断是否稀疏:
- 比较
st_blocks * 512和st_size:若前者远小于后者(比如差几个数量级),基本就是稀疏文件 - Linux 下可查
filefrag -v file看实际 extent 分布 - 不要试图用
lseek + write强制“填满”稀疏区域——除非你真需要那部分空间被分配
跨平台程序里,如果业务依赖“真实磁盘压力”,必须在各平台分别取对应字段,并接受它们语义不完全一致:Linux/macOS 看 st_blocks * 512,Windows 看 AllocationSize,二者底层对齐单位不同,没法做到完全精确映射。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











