# Архивирование файлов

## Введение

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

Перечислим ситуации, в которых можем столкнуться с архивацией:
* отправка по электронной почте каталога;
* формирование дистрибутива программы (инсталлятор, пакет);
* скачивание из GitHub проекта программы ZIP-архивом;
* уменьшение объема занимаемых данных на файловом сервере;
* архивация большого количества небольших файлов для быстрого копирования на флешку;
* ускорение передачи данных по сети;
* файл с расширением `.docx` -- это составной документ, оформленный в виде архива.


## Работа с tar-архивами

Для работы с архивами в UNIX-системах используют утилиту `tar`.
Она позволяет:
* создавать и распаковывать архивы;
* извлекать из архива отдельные файлы;
* добавлять в архив новые файлы;
* просматривать содержимое;

<!-- Создание архива -->
Команда `tar -cf archive.tar file1 file2 file3` объединяет три файла (`file1`, `file2` и `file3`) в архивный файл `archive.tar`.
Если файлы располагаются в каталоге `dir`, то команда `tar -cf archive.tar dir` упаковывает в архив каталог вместе с его содержимым.

<!-- Извлечение файлов из архива -->
Обратную операцию, извлечение, выполняет команда `tar -xf archive.tar`.
Она извлекает в текущий каталог содержимое архива `archive.tar`.
```bash
tar -xf archive.tar
```

Опция `-c` указывает утилите создать архив, а `-x` извлечь содержимое.
Опция `-f` всегда требует аргумент -- имя архива.
При извлечении она должна указывать на существующий файл.
Архивным файлам дают расширение `.tar`.

<!-- Извлечение файлов из архива в отдельный каталог -->
Следует быть осторожнее при извлечении архивов в непустой каталог.
Если файлы в архиве не лежат внутри одного каталога, то такой архив следует извлечь в отдельный пустой каталог.
Иначе извлекаемое содержимое перемешается с уже имеющимися файлами и приведет к беспорядку.
Опция `-C` (`--directory) показывает команде куда следует извлечь содержимое архива:
```bash
tar -xf archive.tar -C newdir
```

То же самое можно было бы сделать несколькими командами:
```bash
mkdir newdir
cd newdir
tar -xf ../archive.tar
```

<!-- Извлечение из архива отдельного файла -->
Если в архиве вас интересуют не все файлы, а конкретные, то их можно извлечь, перечислив имена в команде:
```bash
tar -xf archive.tar file1.txt file2.txt
```

<!-- Просмотр содержимого архива без извлечения -->
Команда `tar -tf archive.tar` выводит на экран содержимое архивного файла в виде списка файлов.

```{note}
Утилита `less` умеет заглядывать внутрь архивов и показывает список файлов.
Попробуйте выполнить команду `less archive.tar`.
```

<!-- Опция `-v` -->
Опция `-v` (`--verbose`) заставляет выводить имена обрабатываемых файлов на экран.


## Компрессия и декомпрессия архива

В UNIX-системах сжатием данных специализируются отдельные утилиты, называемые **компрессорами**.
Обратную операцию, расжатие данных, выполняют **декомпрессоры**.
Для каждого компрессора есть свой декомпрессор, имя которого отличается суффиксом `un`:
* `zip` -> `unzip`;
* `gzip` -> `gunzip`;
* `bzip2` ->`bunzip2`.

Наиболее часто в Linux используют утилиты `gzip` и `bzip2`.
Они сжимают непрерывный поток данных, получаемый или из стандартного потока ввода или файла.
Чтобы сжать несколько файлов или каталогов их используют совместно с архиватором.
Архиватор подготавливает для них поток, превращая несколько файлов в один.

Утилита `tar` для сжатия архива использует компрессор, если указать его опцией.
Так, архив сжимается `gzip`, если задана опция `-z` или утилитой `bzip2` при опции `-j`.
При сжатии первым компрессором, к расширению архива добавляется дополнительно расширение `.gz`, и в конечном счете архив получает расширение `.tar.gz`.
На практике его ужимают до `.tgz`.
```bash
tar -czf archive.tgz dir
```
Извлечение сжатого архива происходит как обычно.
`tar` самостоятельно определяет, каким декомпрессором воспользоваться.
Но, для подстраховки, вы можете передать ей ту же самую опцию:
```bash
tar -xzf archive.tgz
```

Также в системе могут быть доступны другие компрессоры, которые поддерживает `tar`.
Активирующие их опции совпадают с их именами в случае с длинным вариантом.
Перечислим их компрессоры:
* `gzip`;
* `bzip2`;
* `xz`;
* `lzip`;
* `lzop`;
* `lzma`;
* `zstd`;
* `compress`.


## Утилиты `gzip`, `gunzip` и `zcat`

Компрессор `gzip`, представленный одноименной утилитой, использует для сжатия данных алгоритм Лемпеля-Зива, обозначаемый кодовым словом LZ77.
Он сжимает файлы, переданные ему в виде аргументов командной строки:
```bash
bob@pc:~/archive$ ls
file1.txt  file2.txt  file3.txt
bob@pc:~/archive$ gzip file1.txt file2.txt file3.txt 
bob@pc:~/archive$ ls
file1.txt.gz  file2.txt.gz  file3.txt.gz
```

Заметим, что сжимаемые файлы замещаются результатом сжатия, при этом к имени исходного файла добавляется расширение `.gz`.
Обратная операция, декомпрессия, активируется опцией `-d` (`--decompress`):

```bash
bob@pc:~/archive$ ls
file1.txt.gz  file2.txt.gz  file3.txt.gz
bob@pc:~/archive$ gzip -d file1.txt.gz file2.txt.gz file3.txt.gz
bob@pc:~/archive$ ls
file1.txt  file2.txt  file3.txt
```

То же самое можно было бы сделать, если воспользоваться декомпрессором `gunzip`:
```bash
gunzip file1.txt.gz file2.txt.gz file3.txt.gz
```

Здесь мы снова замечаем, что результирующие файлы замещают исходные.
Чтобы сохранить исходные файлы, передайте `gzip` опцию `-k` (`--keep`).


## Утилиты `zip` и `unzip`

Утилита `zip` -- это компрессор, отличающийся от предыдущих тем, что умеет работать с несколькими файлами.
Если архивы `.tgz` используют в частности на машинах с UNIX-системами, то `zip` -- на машинах как UNIX, так и Windows.

```{note}
В разработке ПО не принято использовать архивы `.rar`.
Во-первых, это коммерческий формат, требующий лицензируемой программы для работы с ним.
Во-вторых, это не кроссплатформенно.
```

Следующая команда сжимает каталог `dir` в архив `archive.zip`.
```
zip -r archive.zip dir
```

Обратная операция, распаковка, происходит командой:
```
unzip archive.zip
```

По умолчанию, утилиты `zip` и `unzip`, выводят диагностические сообщения.
Их можно отключить опцией `-q` (`--quiet`).


## Вопросы для самоконтроля

1. Что такое "архив"?
1. Перечислите примеры из жизни, где используются архивация и компрессия данных.
1. Соберите в один архив два отдельных файла и каталог.
1. Что произойдет, если вы создаете архив, который уже существует?
1. Проверьте, какие из перечисленных здесь компрессоров доступны на вашей машине.
1. Опция `--delete` утилиты `tar` удаляет из архива указанный файл.
   Покажите опцию в действии.
1. Проверьте, можно ли удалить файл из сжатого архива.
1. Упакуйте каталог в архив и сравните их размеры.
1. Продемонстрируйте в действии опцию `--list` утилиты `gzip`.
1. `gzip` замещает исходные файлы результатом сжатия/распаковки.
   Какая опция позволяет сохранить исходные файлы?
1. Покажите, что файл с офисным документом (с расширением `.docx`) является zip-архивом.
1. Что делает опция `-c` (`--std-out`, `--to-stdout`) утилиты `gzip`?
   Продемонстрируйте ее в работе.
1. Что делает опция `-r` (`--recursive`) утилиты `gzip`?
   Продемонстрируйте ее в работе.
1. Подсчитайте размер распакованного файла, воспользовавшись конвейером и командами `zcat`, `wc`.
1. Расшифруйте следующую команду:
  `gzip --to-stdout --decompress "infile.tgz" | tar --to-stdout --delete 'file1.txt' -f - | gzip > 'outfile.tgz'` <!-- Удаляет файл из сжатого архива -->
1. Сожмите файлы из каталога `/usr/include` 5-мя разными компрессорами и сравните размеры получившихся архивов.
   Который из компрессоров сжимает сильнее?
   Будьте внимательны, некоторые компрессоры могут отсутствовать.
1. Поместите в архив три файла.
   Последовательно исключайте из архива файлы и выводите список оставшихся файлов.
   Как изменяется размер архива после каждого удаления?
