就地压缩文件 - “gzip -c file | dd of=file”真的有效吗?

就地压缩文件 - “gzip -c file | dd of=file”真的有效吗?

在问题中如何在 Linux 上就地压缩文件而不使用额外的磁盘空间?,一个答案建议简单地使用

gzip -c file | dd of=file

我试过了(在 Debian Linux 上),它确实有效。但我不太明白为什么。

在写入之前不dd截断其输出文件吗?这是否会“拉开地毯” gzip,从而带走 gzip 想要读取的数据?

或者是否存在竞争条件,这意味着命令通常会起作用,但有时可能会失败?或者它是否在某种程度上取决于命令用于 I/O 的块大小?

我知道,一个打开了文件的进程可以继续读取它,即使另一个进程删除了它(一旦进程关闭文件,文件将被丢弃)。如果某个进程打开了文件,而文件被截断,是否有类似的机制?

答案1

实验表明不是工作。

我从 中创建了一个 2 兆字节的文件/dev/urandom,然后尝试了上述命令。结果如下:

% ls -l
total 41008
-rw-r--r-- 1 kst kst 20971520 2012-01-18 03:47 file
-rw-r--r-- 1 kst kst 20971520 2012-01-18 02:48 orig
% gzip -c file | dd of=file
0+1 records in
0+1 records out
25 bytes (25 B) copied, 0.000118005 s, 212 kB/s
% ls -l
total 20508
-rw-r--r-- 1 kst kst       25 2012-01-18 03:47 file
-rw-r--r-- 1 kst kst 20971520 2012-01-18 02:48 orig
$ 

显然是2兆字节随机的文件不会压缩到 25 个字节,实际上,gunzip在压缩文件上运行会产生一个空文件。

对于一个小得多的随机文件(100 字节),我也得到了类似的结果。

所以发生了什么事?

在这种情况下,命令在开始写入之前dd截断为零字节;开始从新空的文件中读取并产生 25 字节的输出,然后将其附加到空的文件中。(空文件“压缩”为非零大小;理论上任何压缩器都不可能做到filegzipddfile全部输入较小)。

gzip还可能出现其他结果,具体取决于、和 shell 进程的时间dd,所有进程都并行运行。

存在竞争条件,因为一个进程gzip从读取file,而另一个并行进程(shell)向其写入。

应该可以实现一个就地文件压缩器,使用任何必要的内部缓冲来读取和写入同一个文件,以避免破坏数据。但我从未听说有人真正实现过这一点,可能是因为这通常没有必要,而且如果压缩器中途失败,文件将永久损坏。

相关内容