Введение в POSIX'ивизм

       

Архивация и компрессия


Архивация и компрессия - это уже не только манипулирование файлами, но и, некоторых образом, изменение их контента. Тем не менее рассмотрим их в этом разделе - ведь с позиций пользователя их смысл близок копированию файлов. И, собственно, целям резервного копирования и архивация, и компрессия призваны служить.

Для пользователя DOS/Windows, привыкшего к программам типа Zip/WinZip, архивация и компрессия неразрывны, как лошади в упряжке. Однако это - разные действия. Архивация - это сборка группы файлов или каталогов в единый файл, содержащий не только данные файлов-источников, но и информацию о них - имена файлов и каталогов, к которым они приписаны, атрибуты принадлежности, доступа и времени, что позволяет восстановить как данные, так и их структуру из архива в первозданном виде. Компрессия же предназначена исключительно для уменьшения объема, занимаемого файлами на диске (или ином носителе).

Для архивации и компрессии предназначены самостоятельные команды. Хотя архивацию и компрессию можно объединить в одной конструкции или представить так, будто они выполняются как бы в едином процессе.

Традиционные средства архивации Unix-систем - команды cpio и tar. Суть первой, как можно понять их названия - копирование файлов в файл архива и из файла архива. Используется она в трех режимах.

Первый режим, copy-out, определяемый опцией -o (или --create), предусматривает считывание списка файлов (name list) со стандартного ввода и объединяет их в архив, который может быть направлен в архивный файл или на устройство для записи резервных копий. Список файлов для архивирования может представлять собой вывод какой-либо иной команды. Так, в примере

$ find ./* | cpio -o > arch.cpio

файлы текущего каталога, найденные командой find, при посредстве команды cpio будут направлены в архивный файл arch.cpio.

Второй режим (copy-in, опция -i, или --extract) осуществляет обратную процедуру: развертывание ранее созданного архива в текущем каталоге:

$ cpio -i < arch.cpio

Здесь нужно заметить, что если разворачиваемый архив включает подкаталоги, автоматически они созданы не будут, и последует сообщение об ошибке.
Для создания промежуточных каталогов команда cpio должна использоваться с опцией -d (--make-directories).

В третьем режиме (copy-pass, опция -p, или --pass-through) команда cpio выполняет копирование файлов из одного дерева каталогов в другой, комбинируя режимы copy-out и copy-in, но без образования промежуточного архива. Список файлов для копирования (name list) считывается со стандартного ввода, а каталог назначения указывается в качестве аргумента:



$ cpio -p dir2 < name_list

Команда cpio имеет множество опций, позволяющих создавать, в частности, архивы в различных форматах (для межплатформенной переносимости). Однако я на них останавливаться не буду, отсылая заинтересованных к соответствующей man-странице: она не кажется мне удобной в применении. И упомянута здесь, во-первых, для полноты картины, во-вторых - универсальности ради (архивы cpio понимаются абсолютно всеми Unix'ами), в третьих - как одно из средств преобразования пакетов, используемых в различных дистрибутивах Linux, друг в друга. Например, утилита rpm2cpio преобразует широко распространенный формат пакетов rpm в еще более универсальный cpio.

Основным же средством архивирования во всех Unix-системах является команда tar. Обобщенный формат ее -

$ tar [options] archiv_name [arguments]

где archiv_name - обязательный аргумент, указывающий на имя архивного файла, с которым производятся действия, определяемые главными опциями. Формы указания опций для команды tar очень разнообразны. Исторически первой была краткая форма без предваряющего дефиса, что поддерживается и поныне. Однако в текущих версиях команды в целях единообразия утверждена краткая форма с предваряющим дефисом или дублирующая ее полная форма, предваряемая двумя дефисами. Некоторые опции (например --help - получение справки об использовании команды) предусмотрены только в полной форме.

Главные опции и указывают на то, какие действия следует выполнить над архивом в целом:

  • создание архива (опция c, -c или --create);


  • просмотр содержимого существующего архива (опция t, -t или --list);




  • распаковка архива (опция x, -x, --extract или --get).


  • Легко понять, что при работе с архивом как целым одна из этих главных (т.н. функциональных) опций обязательна. При манипулировании же фрагментами архива они могут подменяться другими функциональными опциями, как то:

  • r (или --append) - добавление новых файлов в конец архива;


  • u (или --update) - обновление архива с добавлением не только новых, но и модифицированных (с меньшим значением атрибута mtime) файлов;


  • -A (--catenate или --concatenate) - присоединение одного архива к другому;


  • --delete - удаление именованных файлов из архива;


  • --compare - сравнение архива с его источниками в файловой системе.


  • Прочие (очень многочисленные) опции можно отнести в разряд дополнительных - они определяют условия выполнения основных функций команды. Однако одна из таких дополнительных опций - f (-f или --file), значение которой - имя файла (в том числе файла устройства, и не обязательно на локальной машине), также является практически обязательной. Дело в том, что команда tar (от tape archiv) изначально создавалась для прямого резервного копирования на стриммерную ленту, и именно это устройство подразумевается в качестве целевого по умолчанию. Так что если это не так (а в нынешних условиях - не так почти наверняка), имя архивного файла в качестве значения опции f следует указывать явно. Причем некоторые реализации команды tar требуют, чтобы в списке опций она стояла последней.

    Проиллюстрируем сказанное несколькими примерами. Так, архив из нескольких файлов текущего каталога создается следующим образом:

    $ tar cf arch_name.tar file1 ... file#

    Если задать дополнительную опцию v, ход процесса будет отображаться на экране - это целесообразно, и в дальнейших примерах эта опция будет использоваться постоянно.

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

    $ tar cvf arch_name.tar *

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


    А командой

    $ tar cvf arch_name.tar dir

    каталог dir будет упакован с полным сохранением его структуры.

    С помощью команды

    $ tar xvf arch_name.tar

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

    При извлечении файлов из архива никто не обязывает нас распаковывать весь архив - при необходимости это можно сделать для одного нужного файла, следует только указать его имя в качестве аргумента:

    $ tar xvf arch_name.tar filename

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

    $ tar tf arch_name.tar

    Если архив собирался по первой схеме (с именами файлов в качестве аргументов, вывод ее будет примерно следующим:

    dir2/ dir2/file1 example new newfile tee.png

    При втором способе архивации мы увидим на выводе нечто вроде

    dir1/ dir1/example dir1/new dir1/newfile dir1/tee.png dir1/dir2/ dir1/dir2/file1

    В данном примере опция v была опущена. Включение ее приведет к тому, что список файлов будет выведен в длинном формате, подобном выводу команды ls -l:

    drwxr-xr-x alv/alv 0 10 май 11:03 2002 dir2/ -rw-r--r-- alv/alv 0 10 май 11:03 2002 dir2/file1 ...

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

    Команд для компрессии файлов несколько, но реальный интерес ныне представляют две парные утилиты - gzip/gunzip и bz2/bunzip2.


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

    Команда gzip - это традиционный компрессор Unix-систем, сменивший в сей роли более старую утилиту compress. Простейший способ ее использования -

    $ gzip filename

    где в качестве аргументов будет выступать имя файла. При этом (внимание!) исходный несжатый файл подменяется своей сжатой копией, которой автоматически присваивается расширение *.gz.

    В качестве аргументов может выступать и произвольное количество имен файлов - каждый из них будет заменен сжатым файлом *.gz. Более того, посредством опции -r может быть выполнено рекурсивное сжатие файлов во всех вложенных подкаталогах. Подчеркну, однако, что никакой архивации команда gzip не производит, обрабатывая за раз только единичный файл. Фактически форма

    $ gzip file1 file2 ... file#

    просто эквивалент последовательности команд

    $ gzip file1 $ gzip file2 ... $ gzip file#

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

    Команда gzip имеет и другие опции, указываемые в краткой (однобуквенной) или полной нотации. В отличие от tar, знак дефиса (или, соответственно, двойного дефиса) обязателен в обоих случаях. Так, опциями -1 ... -9 можно задать степень сжатия и, соответственно, время исполнения процедуры: -1 соответствует минимальному, но быстрому сжатию, -9 - максимальному, но медленному. По умолчанию в команде gzip используется опция -6, обеспечивающая разумный компромисс между скоростью и компрессией.

    Благодаря опции -d (--decompress) команда gzip может выполнить развертывание сжатого файла, заменяя его оригиналом без расширения *.gz. Хотя в принципе для этого предназначена команда gunzip:

    $ gunzip file.gz

    Использование этой команды настолько прозрачно, что я задерживаться на ней не буду.



    В последнее время широкое распространение получил компрессор bzip2, обеспечивающий большую (на 10-15%) степень сжатия, хотя и менее быстродействующий. Использование его практически идентично gzip, с деталями его можно ознакомиться с помощью страницы экранной документации man bzip2. Итоговый компрессированный файл получает имя вида *.bz2 и может быть распакован командой bunzip2 (или командой bzip2 -d). Следует только помнить, что форматы *.gz и *.bz2 не совместимы между собой. Соответственно, первый не может быть распакован программой bunzip2, и наоборот.

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

    $ tar cvzf dir.tar.gz dir/

    Обратите внимание, что суффикс *.gz в этом случае нужно указывать в явном виде - автоматически оно к имени архива не присоединяется и компрессированный архив будет иметь вид dir.tar. Поскольку в Unix расширения имен файлов не играют той сакральной роли, что в MS DOS, это не помешает распаковке такого файла командой

    $ tar xvzf dir.tar

    Опция z сама по себе никакой компрессии не выполняет - она просто вызывает компрессор gzip для сжатия каждого из архивируемых файлов. Аналогичный смысл имеет и опция j - только ею для этой цели привлекается команда bzip2 (в некоторых системах для вызова последней из команды tar используется опция y).

    При использовании команды tar с опцией z (или j) исходные файлы остаются в неприкосновенности. Следует, однако, помнить, что архив сжатых файлов не может быть обновлен командой tar с параметрами r или u.

    Есть и другой способ совместной архивации и компрессии - просто последовательность команд

    $ tar cf dir.tar * $ gzip dir.tar

    В результате образуется сжатый архив - внешне такой же файл dir.tar.gz. Хотя в принципе архив сжатых файлов и сжатый архивный файл - это разные вещи (можно заметить, что они даже различаются по объему, хотя и всего на несколько байт), сжатый архив также может быть благополучно развернут командой tar с опцией z.И столь же очевидно, что он не может быть ни пополнен, ни обновлен средствами архиватора tar.

    Компрессированные архивы, созданные сочетанием программ tar и gzip/bzip2 - общепринятый в Unix-системах метод распространения файлов. Однако иногда для совместимости с ОС, не допускающими двух точек в имени файла (знаете такую ОС?), компрессированным tar-архивам присваивается суффикс *.tgz. Можно встретить и файлы с маской *.tbz2 (или даже *.tbz - именно такой вид имеют пакеты в 5-й ветке FreeBSD). Нетрудно догадаться, что это те же архивы *.tar.bz2.


    Содержание раздела