Linux stat命令Blocks字段与IO Block字段的理解
原因
在之前了解文件系统的时候,为理解块与扇区的概念,用到了stat命令。
关于这个命令输出的信息的文章有很多,其他字段是没有争议的,但是在一些文章中对Blocks与IO Block理解有错误。
结论
先说结论
Blocks字段指的是512字节构成的块的个数,IO Block是指文件系统的块的大小一般为4096字节。
它们关系如下
$$ IO\space Block = Blocks\times 512B $$
网上有很多文章说Blocks字段指的是文件系统中块的个数,这个是错误的。实践是检验真理的唯一标准,下面我们就直接查看Linux的stat命令的源码验证一下。
验证
首先终端执行以下命令,搜索stat所在目录
which stat
得到如下结果
然后再搜索软件所在包
dpkg -S /usr/bin/stat
发现是在coreutils包下
去GNU的网站下载这个包
然后解压缩,于src文件夹下和lib文件夹下分别查看stat.c这个源文件发现并没有与这两个字段相关的类型定义,这看似我们寻找失败了。但是经过一段时间摸索,在lib下的stat.c中包含了sys/stat.h头文件,我们想要找的答案很可能就在这里面
利用清华大学镜像源加速,获取glibc,解压后在usr/include目录下终于找到了stat.h头文件
查看内容,果然有一个名为stat的结构体,代码片段如下
struct stat
{
unsigned int st_dev; /* Device. */
unsigned int st_ino; /* File serial number. */
unsigned int st_mode; /* File mode. */
unsigned int st_nlink; /* Link count. */
unsigned int st_uid; /* User ID of the file's owner. */
unsigned int st_gid; /* Group ID of the file's group.*/
unsigned int st_rdev; /* Device number, if device. */
long int st_size; /* Size of file, in bytes. */
unsigned long int st_atime; /* Time of last access. */
unsigned long int st_mtime; /* Time of last modification. */
unsigned long int st_ctime; /* Time of last status change. */
unsigned int st_blksize; /* Optimal block size for I/O. */
#define _STATBUF_ST_BLKSIZE /* Tell code we have this member. */
int st_blocks; /* Nr. of 512-byte blocks allocated. */
unsigned int st_flags;
unsigned int st_gen;
};
找到名st_blocks的结构体成员,右边的注释写着“512-byte blocks”,这显然说明stat命令的Blocks字段含义就是以512字节为单位的个数。
为什么是512?因为早期的机械硬盘扇区大小为512字节,但现在无论SSD还是机械,存储单位都是4096字节的了,正好是512的整数倍。
而IO Block是指文件系统中的块的大小,对应st_blksize成员,相当于8个512字节块(对于512字节扇区的磁盘来讲,在物理上表现为8个连续的扇区),即4096字节。
而这个512字节的块究竟是物理块还是逻辑块?由于现在存储设备的发展,以及不同文档中有不同定义,这些东西的概念十分模糊,所以我并不建议把它理解成一个实际存在的块,而是作为一个基本单位。笔者认为在学习文件系统的时候只需要知道,文件系统中的块相当于8个这样的连续的基本单位组成就足够了。
其他
通过阅读代码可以发现在Linux中,stat命令所说的Size字段指的是文本大小,而不是文件实际占用大小。
Size字段对应stat结构体st_size成员,该字段数值并不等于IO Block*Blocks(而Windows中是这样)。
文件的实际占用空间应该为 文件系统的块大小*文件文件系统块的个数
即
$$ TrueSize = FileBlock \times FileBlockNum $$