stat命令如何计算文件的块数?

14

我想知道 stat 命令如何计算文件的块数。我阅读了这篇文章,其中写到:

st_blocks 的值以 512 字节块为单位给出文件的大小。(例如当文件存在空洞时可能比 st_size/512 更小)。st_blksize 的值是有效文件系统 I/O 操作的“首选”块大小。(以更小的块写入文件可能导致低效的读取-修改-重写操作。)

然而,我无法通过自己的测试进行验证。

我的文件系统是 ext3。

命令 dumpe2fs -h /dev/sda3 显示:

...
First block: 0
Block size: 4096
Fragment size: 4096
...

然后我运行

kent@KentT60:~/Desktop$ stat Email
File: `Email'
Size: 965 Blocks: 8 IO Block: 4096 regular file
Device: 80ah/2058d Inode: 746095 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ kent) Gid: ( 1000/ kent)
Access: 2009-08-11 21:36:36.000000000 +0200
Modify: 2009-08-11 21:36:35.000000000 +0200
Change: 2009-08-11 21:36:35.000000000 +0200
如果这里的“块”指的是“多少个512字节的块”,那么数字应该是2,而不是8。我认为文件系统(IO块)的块大小是4k。
如果文件系统获取名为Email的文件,它将从磁盘中取出至少4k(8 x 512字节块),这意味着965/512 + 6 = 8。我不确定这个猜测是否正确。
另一个测试:
kent@KentT60:~/Desktop$ stat wxPython-demo-2.8.10.1.tar.bz2
File: `wxPython-demo-2.8.10.1.tar.bz2'
Size: 3605257 Blocks: 7056 IO Block: 4096 regular file
Device: 80ah/2058d Inode: 746210 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ kent) Gid: ( 1000/ kent)
Access: 2009-08-12 21:45:45.000000000 +0200
Modify: 2009-08-12 21:43:46.000000000 +0200
Change: 2009-08-12 21:43:46.000000000 +0200


3605257/512=7041.xx = 7042

根据我的猜测,答案是7042+6=7048。但是stat的结果显示为7056。

还有一个来自于网站https://www.computerhope.com/unix/stat.htm的例子。我将这个例子贴在了页面底部:

File: `index.htm'
Size: 17137 Blocks: 40 IO Block: 8192 regular file
Device: 8h/8d Inode: 23161443 Links: 1
Access: (0644/-rw-r--r--) Uid: (17433/comphope) Gid: ( 32/ www)
Access: 2007-04-03 09:20:18.000000000 -0600
Modify: 2007-04-01 23:13:05.000000000 -0600
Change: 2007-04-02 16:36:21.000000000 -0600
在这个示例中,文件系统块大小为8k。我认为“Blocks”值应该是16xN,但它是40。我感到迷惑...
有人能解释一下`stat`如何计算“Blocks”值吗?
谢谢!

stat 的输出有点棘手: "Blocks" 的块大小为 512 字节,而 "IO Block" 的块大小通常为 4096 字节(对于 ext4)。我试图在 这个答案 中深入了解这个问题。 - Matthias Braun
2个回答

22
stat命令行工具使用stat / fstat等函数来返回stat结构中的数据。stat结构的st_blocks成员返回以下内容:
总共分配在磁盘上的实际大小为512字节的物理块数。对于块特殊文件或字符特殊文件,此字段未定义。
因此,对于您的“电子邮件”示例,其大小为965,块计数为8,表示在磁盘上物理分配了8 * 512 = 4096个字节。之所以不是2,是因为磁盘上的文件系统未按512的单位分配空间,它显然按4096的单位分配空间。(分配单元可能会根据文件大小和文件系统复杂程度而有所不同。例如,ZFS支持不同的分配单元。)
类似地,对于wxPython示例,它表示在磁盘上物理分配了7056 * 512字节,即3612672字节。你懂的。
IO块大小是“最适合I / O操作的单位大小的提示”-通常是物理磁盘上的分配单元。不要混淆IO块和stat用于指示物理大小的块;物理大小的块始终为512字节。
基于评论的更新:
像我说的那样,st_blocks是操作系统指示文件在磁盘上使用了多少空间的方式。实际上分配在磁盘上的分配单元是文件系统的选择。例如,ZFS可以具有可变大小的分配块,甚至可以在同一个文件中,因为它分配块的方式:文件开始时具有较小的块大小,并且块大小不断增加直到达到特定点。如果稍后截断文件,则可能保留旧块大小。因此,基于文件的历史记录,它可以具有多个可能的块大小。因此,对于给定的文件大小,往往不明显为什么会有特定的物理大小。
具体例子:在我的Solaris框架上,使用ZFS文件系统,我可以创建一个非常短的文件:
$ echo foo > test
$ stat test
  Size: 4               Blocks: 2          IO Block: 512    regular file
(irrelevant details omitted)

好的,这是一个小文件,由两个块组成,物理磁盘使用量为1024。

$ dd if=/dev/zero of=test2 bs=8192 count=4
$ stat test2
  Size: 32768           Blocks: 65         IO Block: 32768  regular file

现在我们看到物理磁盘使用量为32.5K,IO块大小为32K。然后我将其复制到test3中,并在编辑器中截断了这个test3文件:

$ cp test2 test3
$ joe -hex test3
$ stat test3
  Size: 4               Blocks: 65         IO Block: 32768  regular file

这是一个含有4个字节的文件,就像test一样,但由于ZFS文件系统分配空间的方式,它需要物理上占用32.5K的磁盘空间。随着文件越来越大,块大小也会增加,但当文件变小时并不会减少。(是的,这可能会导致浪费大量的空间,具体取决于您在ZFS上执行的文件和文件操作类型,这就是为什么它允许您按照每个文件系统的设置最大块大小,并且可以动态更改。)

希望现在您能够认识到文件大小和物理磁盘使用之间并不一定存在简单的关系。即使在上述情况下,为什么需要32.5K字节来存储一个完全大小为32K的文件也不清楚 - 看起来ZFS通常需要额外的512字节来存储自己的额外数据。也许它正在使用该存储空间进行校验和、引用计数、交易状态 - 文件系统记账。通过将这些额外内容包含在指定的物理文件大小中,似乎ZFS试图不误导用户关于文件的物理成本。这并不意味着在不知道底层文件系统实现的细节的情况下轻松地反向工程计算。


同意。st_blocks之所以被称为“块”,只是出于历史原因。不要把它看作块,而是文件使用的磁盘空间量,以512字节为单位。512字节是一个方便的单位,因为它几乎是任何人使用的最小分配单位。 - mark4o
谢谢您的解释,我差不多明白了。但还有一些问题。我不确定我的理解是否正确:st_blocks =(IO块大小/ 512)(文件使用的IO块数)。 电子邮件示例可以通过此进行解释:(4096/512) 1 = 8 wxpython则不行。因为该文件使用了881个IO块,而(4096/512)* 881 = 7048而不是7056。最后一个示例也不行: 40甚至无法被16(8192/512)整除。“512字节”对于所有系统都是相同的吗?谢谢 - Kent

0
我不是在谈论像ZFS这样复杂的文件系统, 而是关于像ext2这样简单的文件系统: -stat输出字段“IO Block”显示“ext2文件系统块大小”。 -stat输出字段“Blocks”显示不存在的虚拟块数(每个512字节)。也就是说,stat根据“Size”字段给出文件大小,将其除以512并放入答案中。
举个例子, 一个文件的大小为2字节。
# od -t x1 ./1
0000000 31 0a
0000002

一个文件系统被格式化为4K的fs块大小 让我们来看一下stat
# stat 1
  File: 1
  Size: 2           Blocks: 8          IO Block: 4096   regular file
Device: 811h/2065d  Inode: 12          Links: 1

IO Block显示4096,即4K,即ext2文件系统块大小。由于文件不能占用小于文件系统块大小的空间,所以2个字节驻留在一个文件系统块中,4K = 4096字节。 我们将4096除以512得到8。这是“Blocks”字段中的数字。
让我们再来看一个文件系统块大小为1K的ext2文件系统。
# stat 1
  File: 1
  Size: 2           Blocks: 2          IO Block: 1024   regular file

IO块=1024,这正是文件系统块大小(1K)。

文件不能占用少于1K的磁盘空间。所以2字节占用1K的磁盘大小。

我们将1024除以512得到2。 这正是我们看到的。

Blocks: 2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接