6

В вопросе Как я могу сжать файл в Linux на месте, не используя дополнительное место на диске? один ответ предлагает просто использовать

gzip -c file | dd of=file

Я попробовал это (на Debian Linux), и это, кажется, работает. Однако я не совсем понимаю, почему.

Разве dd не обрезает свой выходной файл перед записью? Разве это не "вытаскивает коврик" под gzip , тем самым убирая данные, которые gzip хочет прочитать?

Или есть какое-то условие гонки, означающее, что команда обычно работает, но может иногда терпеть неудачу? Или это как-то зависит от размеров блока, которые команды используют для ввода-вывода?

Я знаю, что процесс, открывший файл, может продолжить его чтение, даже если другой процесс удалит его (файл будет удален, как только процесс закроет его). Существует ли подобный механизм, если файл усекается, когда какой-то процесс открывает его?

1 ответ1

4

Эксперимент показывает, что это не работает.

Я создал 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 усекает file до нуля байтов перед началом записи в него; gzip начал чтение из нового пустого файла и выдал 25 байтов вывода, который затем dd добавлялся в пустой file . (Пустой файл "сжимается" до ненулевого размера; для любого компрессора теоретически невозможно сделать все входные данные меньшими).

Другие результаты могут быть возможны, в зависимости от времени процессов gzip , dd и shell, все из которых работают параллельно.

Есть условие гонки, потому что один процесс, gzip , читает из file , в то время как другой параллельный процесс, оболочка, пишет в него.

Должна быть возможность реализовать встроенный файловый компрессор, который читает и записывает в один и тот же файл, используя любую внутреннюю буферизацию, необходимую для предотвращения скопления данных. Но я никогда не слышал о том, чтобы кто-нибудь на самом деле реализовывал это, возможно потому, что это обычно не нужно и потому что если компрессор не работает на полпути, файл будет навсегда поврежден.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .