ls 中的文件大小存在奇怪的差异

ls 中的文件大小存在奇怪的差异

ls -sh从 1997 年左右开始,我就一直在检查文件大小,但今天发生了一些奇怪的事情:

ninja@vm:foo$ ls -sh
total 98M
1,0M app   
64M app_fake_signed.sbp  
800K loader  
804K loader_fake_signed.sbp  
1,0M web   
32M web_fake_signed.sbp

app和文件web不应该比签名的文件小很多,我花了几个小时调试签名程序。在一无所获之后,我偶然查看了 Samba 共享中的文件,发现它们的大小非常相似。我又查了一下:

ninja@vm:foo$ ls -lh
total 98M
-rw-rw-r-- 1 ninja ninja  63M lut  4 14:13 app
-rw-rw-r-- 1 ninja ninja  64M lut  4 14:13 app_fake_signed.sbp
-rw-rw-r-- 1 ninja ninja 800K lut  4 14:13 loader
-rw-rw-r-- 1 ninja ninja 801K lut  4 14:13 loader_fake_signed.sbp
-rw-rw-r-- 1 ninja ninja  31M lut  4 14:13 web
-rw-rw-r-- 1 ninja ninja  32M lut  4 14:14 web_fake_signed.sbp

我无语了?为什么ls -s显示app和 的web大小为 1MB,而实际上它们分别为 63 和 32MB?

如果有什么区别的话,这是在 Windows 上的 VirtualBox 中运行的 Xubuntu 14.04。

编辑: 文件appwebloader都是由dd if=/dev/urandom of=app bs=$BLOCK count=1 seek=...循环运行的 bash 脚本(不是我的设计)创建的。用 C 语言编写的签名程序获取这些文件并将其签名版本写入磁盘,并在每个文件前面和后面附加一个二进制签名。

答案1

您正在使用 的-s选项ls

文件的大小及其占用的磁盘空间量可能有所不同。例如,考虑一下,如果您打开新文件,在其中查找 1G,并写入“某物”,则操作系统不会在磁盘上分配 1G(加上“某物”的空间),它只为“某物”分配空间 - - 这被称为稀疏文件

我编写了一个小 C 程序来创建这样的文件:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
    int fd = open("/tmp/foo.dat", O_CREAT | O_WRONLY, 0600);

    if (fd > 0) {
        const off_t GIG = 1024 * 1024 * 1024;

        // Seek 1G into the file
        lseek(fd, GIG, SEEK_SET);

        // Write something
        write(fd, "hello", sizeof "hello");

        close(fd);
    }

    return 0;
}

运行该程序我得到:

$ ls -lh /tmp/foo.dat
-rw------- 1 user group 1.1G Feb  4 15:25 /tmp/foo.dat

但是使用-s,我得到:

$ ls -sh /tmp/foo.dat
4.0K /tmp/foo.dat

因此,在磁盘上分配了一个 4K 块来存储“hello”(4K 是我的文件系统的最小分配单位)。

就您而言,它看起来像app并且web是非常稀疏的文件。

答案2

ls -s列出文件内容使用的存储空间量(不包括用于元数据的空间)。这可能与文件大小有两个不同之处:

  • 在大多数情况下,文件大小会向上舍入为整数块。块的大小通常为 512B 到 4kB,但这取决于文件系统(有些文件系统没有这个概念)。
  • 如果文件以某种方式编码,例如压缩,则文件大小可能会更小(或更大)。

Unix 文件系统支持一种粗略的压缩形式,称为稀疏文件:如果文件中的块完全由空字节组成,则根本不需要存储它;文件系统在存储文件内容的块列表中放置一个特殊标记而不是块号。这种压缩方法不是系统性的:如果程序写入一堆空字节,它们就会被存储。然而,Unix 也允许程序写入超过文件末尾的内容。在这种情况下,文件将使用空字节进行扩展,但如果这些字节构成整个块或更多块,则不会存储这样的整个空块。

当您写入 时dd seek=…dd程序会在开始写入之前寻找给定的位置。以您的情况为例app,该位置似乎已超过文件末尾约 62MB,因此大约有 62MB 的空字节隐式存储在不存在的块中。此存储详细信息不会暴露给应用程序(除非它们使用不可移植的接口来查找,但很少这样做),因此当签名程序读取其输入时,它只知道有大约 63MB 的数据,因此它将 63MB 写入其输出文件,其中约 62MB 为空字节。

如果您确实需要磁盘空间,您可以事后使文件稀疏。这种情况很少发生,因为大多数文件没有大的零块,因此运行工具来查找它们会浪费大量时间。

相关内容