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。
编辑:
文件app
、web
和loader
都是由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 为空字节。
如果您确实需要磁盘空间,您可以事后使文件稀疏。这种情况很少发生,因为大多数文件没有大的零块,因此运行工具来查找它们会浪费大量时间。