О gzip
2016-05-02
Издавна файлы упаковывались и сжимались. Часто для экономии дискового пространства. Или же для передачи по сети. И как-то повелось, что сжимать нужно было сразу целые кучки файлов. Так родились такие милые форматы архивов, как Zip или Rar. Они выполняют сразу две задачи: засунуть кучу файлов в один файл и сжать всё это дело.
В мире Unix
принято поступать своим путём.
И эти две задачи разделены.
За то,
чтобы поместить кучу файлов
в один большой файл,
отвечает tar
.
Вообще-то,
это — tape archiver,
т.е. архиватор на ленту.
Давным давно файлы нужно было засовывать
в один непрерывный файл-поток
для записи на магнитную ленту.
Так и получался архив.
А вот сжатие архива делается отдельно.
Формально,
внешними утилитами.
Такими,
как gzip
,
bzip2
,
а в последнее время,
ещё и lzma
и xz
.
gzip
использует
тот же алгоритм сжатия Deflate,
что и классический Zip.
А lzma
и xz
реализуют алгорим LZMA (и LZMA2),
те же,
что в 7-zip.
Получается,
что .tar.gz
—
это куча файлов в одном tar архиве,
сжатое с помощью gzip
.
Это в некотором смысле противоположно zip архиву,
где сначала сжимается каждый файл,
а потом они помещаются в один архив.
С другой стороны,
у Rar и 7-zip есть возможность создания
непрерывных
(solid) архивов,
когда всё происходит
как в .tar.gz
:
сначала соединяем файлы,
а потом всё жмём.
Юниксовые компрессоры gzip
, bzip2
, xz
могут работать и без tar
,
сжимая один единственный файл.
Как-то так:
% gzip big_long.log
gzip
жмёт похуже,
bzip2
— получше,
xz
— ещё лучше.
Но gzip
жмёт всё же вполне прилично.
Допустим, у нас есть какой-то дурацкий лог-файл. Аж на 10 гигабайт.
% ls -s *.log
11002376 big_long.log
Этот файлик можно, конечно, засунуть в 7z архив.
% time 7z a big_long.7z big_long.log
7-Zip [64] 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18
p7zip Version 9.20 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,4 CPUs)
Scanning
Creating archive big_long.7z
Compressing big_long.log
Everything is Ok
7z a big_long.7z big_long.log 1955.19s user 33.48s system 118% cpu 28:03.36 total
Почти полчаса на то, чтобы сжать. Зато сжалось хорошо.
% ls -s1 *.log *.7z
281720 big_long.7z
11002376 big_long.log
Сжалось аж почти в сорок раз.
Что с этим архивом можно сделать? Ну, распаковать.
% time 7z x big_long.7z
7-Zip [64] 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18
p7zip Version 9.20 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,4 CPUs)
Processing archive: big_long.7z
Extracting big_long.log
Everything is Ok
Size: 11266426416
Compressed: 288475059
7z x big_long.7z 39.95s user 8.17s system 33% cpu 2:22.03 total
За две с половиной минуты мы можем получить наши десять гигабайт обратно.
Попробуем gzip
.
% time gzip big_long.log
gzip big_long.log 125.82s user 4.13s system 87% cpu 2:29.06 total
Ухты.
Две с половиной минуты на упаковку.
Вместо получаса у 7z
.
А что с размером?
% ls -s1 *.log *.gz
11002376 big_long.log
456112 big_long.log.gz
Сжалось в два раза хуже. Но всё равно, четыреста пятьдесять мегабайт — это сильно транспортабельнее, чем десять гигабайт.
Что можно сделать с этим архивом? Можно распаковать.
% time gunzip big_long.log.gz
gunzip big_long.log.gz 39.73s user 7.69s system 29% cpu 2:38.33 total
За те же две с половиной минуты.
Но можно и не распаковывать. Да.
Зачем нам этот лог?
Файлик в десять гигабайт невозможно открыть ни в одном текстовом редакторе,
памяти не хватит.
Даже less
не поможет,
он тоже грузит файл в память.
Его долго и проблематично грузить во всякие
логстэши,
в любом случае потребуется больше десяти гигов
для хранения этой прелести.
А я не хочу хранить,
мне нужно найти пару десятков
или сотен
строк,
относящихся к определённому моменту.
Нам нужен grep
.
Погрепаем десятигиговый файл.
% time grep "12:43:58" < big_long.log > big_long.grep_12_43_58.log
grep "12:43:58" < big_long.log > big_long.grep_12_43_58.log 9.32s user 7.55s system 13% cpu 2:07.35 total
Чуть больше двух минут на то, чтобы прочесть и профильтровать десять гигов, и получить сто семь строчек в двадцати семи килобайтах того, что нужно, и что можно открыть в редакторе.
Но gzip архивы можно грепать без распаковки.
% time zgrep "12:43:58" < big_long.log.gz > big_long.zgrep_12_43_58.log
zgrep "12:43:58" < big_long.log.gz > big_long.zgrep_12_43_58.log 48.25s user 3.80s system 116% cpu 44.796 total
Сорок пять секунд, и абсолютно тот же результат.
Как это работает?
gzip — это поток,
именно потому его используют веб-серверы для сжатия контента.
Можно читать сжатые данные,
разжимать их поблочно,
сравнивать и грепать.
Именно так и работает zgrep
.
Нет необходимости загружать все десять гигов в память,
всё будет распаковываться маленькими кусочками
по мере необходимости.
А с диска читать нужно только сжатые данные,
которых в двадцать раз меньше.
Есть куча других утилит,
которые могут работать с файлами,
сжатыми gzip
,
без явной распаковки.
Собственно,
zgrep
— это,
по сути,
комбинация zcat
и обычного grep
.
А есть ещё
zdiff
, zmore
и zless
.
Кстати, есть и bzgrep
, и xzgrep
.
Попробуем bzip2
.
% time bzip2 big_long.log
bzip2 big_long.log 2173.18s user 5.57s system 95% cpu 37:59.61 total
Доолго.
% ls -s *.bz2
250208 big_long.log.bz2
Сжал даже лучше, чем 7z
.
Погрепаем.
% time bzgrep "12:43:58" < big_long.log.bz2 > big_long.bzgrep_12_43_58.log
bzgrep "12:43:58" < big_long.log.bz2 > big_long.bzgrep_12_43_58.log 249.57s user 11.47s system 106% cpu 4:05.09 total
Тоже долго. Дольше, чем читать несжатый файл.
Попробуем xz
.
% time xz big_long.log
xz big_long.log 2326.37s user 6.65s system 98% cpu 39:18.39 total
Тоже долго.
% ls -s *.xz
253300 big_long.log.xz
Так же компактно.
Грепаем.
% time xzgrep "12:43:58" < big_long.log.xz > big_long.xzgrep_12_43_58.log
xzgrep "12:43:58" < big_long.log.xz > big_long.xzgrep_12_43_58.log 46.81s user 6.83s system 127% cpu 42.044 total
А вот тут быстро,
почти как с gzip
.
Выводы.
Не засовывайте логи в архивы типа Zip, 7-zip, Rar.
Сжимайте их в .gz
.
Тогда можно будет их обрабатывать без полной распаковки.
Згрепать можно даже очень большие файлы.
Если хочется сэкономить ещё немного места,
можно взять bzip2
или xz
вместо gzip
,
но помните,
что gzip
пакует значительно быстрее.
размер (в блоках) | время сжатия | время грепа | |
---|---|---|---|
исходный файл, grep | 11002376 | — | 02:07 |
gzip, zgrep | 456112 | 02:29 | 00:44 |
bzip2, bzgrep | 250208 | 37:59 | 04:05 |
xz, xzgrep | 253300 | 39:18 | 00:42 |
7z | 281720 | 28:03 | — |