С помощью Python можно работать с архивами: сжимать и распаковывать. Сегодня расскажем вам о 7 стандартных библиотках, которые помогут вам для работы со сжатием и архивированием. Читайте в этой статье: как сжать данные извлечь из zip, tar, bz2, xz с помощью Python.
Какие библиотеки есть в Python для сжатия данных
Одно из преимуществ Python — это наличие библиотек, которые решают чуть ли не все насущные проблемы. Так вот для сжатия данных в практически любой формат Python-библиотек огромное множество. К стандартным относятся следующие модули:
1) zlib служит для сжатия данных на основе алгоритма Deflate [1].
2) gzip использует уже алгоритм сжатия zlib и служит интерфейсом, аналогичным утилитам gzip и gunzip.
3) lzma использует алгоритм LZMA [2] для сжатия, поддерживает форматы xz и lzma.
4) shutil высокоуровневый модуль для работы с архивами разных форматов. Мы, кстати, использовали его тут.
5) bz2 служит для сжатия bzip2, алгоритм сжатия эффективнее вышеупомянутого Deflate, но работает медленней.
6) zipfile предназначен для работы с zip-файлами, причем модуль предоставляет возможность создавать, читать, записывать и добавлять в архив.
7) tarfile предназначен для работы с tar, поддерживает сжатия форматов gzip, bz2 и lzma.
Сжатие и распаковка данных
Если вам понадобилось сжать или распаковать данные, то уже по названию модуля можно понять, какой из них использовать. При этом они все со схожим интерфейсом. Рассмотрим библиотеку zlib. Она низкоуровневая, поэтому не часто используется. Для сжатия используется функция compress
, для распаковки — decompress
.
Для начала создадим бинарный файл размером 1 МБ и заполним его нулям с помощью псевдоустройства /dev/zero
:
$ head -c 1MB </dev/zero > data
Для сжатия нужно указать level
(уровень сжатия), которые также берутся из модуля zlib.
filename_in = "data" filename_out = "compressed" with open(filename_in, mode="rb") as fin: data = fin.read() with open(filename_out, mode="wb") as fout: compressed = zlib.compress(data, zlib.Z_BEST_COMPRESSION)
Размер получившегося архива равен 1024 байт. Иными словами, мы сжали данные в 3 раза. Распаковка архива выполняется схожим образом:
with open(filename_out, mode="rb") as fin: decompressed = zlib.decompress(fin.read())
Библиотека bz2 работает немного по-другому. У неё есть функция open
, которая ведёт себя так же как и встроенная функция Python. Поэтому для сжатия требуется записать в файл, а для распаковки на чтение:
import bz2 filename_in = "data" filename_out = "compressed.bz2" # Compress with open(filename_in, mode="rb") as fin: data = fin.read() with bz2.open(filename_out, "wb") as fout: fout.write(data) # Decompress with bz2.open(filename_out, "rb") as fin: data = fin.read()
В результате файл bz2
имеет размер 48 байт, что даже лучше того, как сжимает zlib.
Читайте файлы порциями, когда данные большого размера
Файлы могут быть большими, поэтому читать всё сразу может не получиться. Для этого стоит использовать прочитывать порциями с помощью метода chunk
. Рассмотрим его на примере библиотеки lzma. Вместо того чтобы сжимать/распаковывать бинарный файл, возьмём текстовый файл, например, HTML-файл с одной из статей данного сайта.
Код курса
DREP
Ближайшая дата курса
по запросу
Продолжительность
ак.часов
Стоимость обучения
0 руб.
Библиотека lzma может работать на уровне объектов (хотя функция open
тоже имеется). Объектом для сжатия является экземпляр класса LZMACompressor
, для распаковки — LZMADecompressor
(хотя обычные функции compress
и decompress
там тоже имеются). Мы воспользуемся данными классами для иллюстрации.
Итак, разбиение на порции по 1024 байта и сжатие данных через lzma в Python выглядит следующим образом:
import lzma lzc = lzma.LZMACompressor() filename_in = "data" filename_out = "compressed.xz" with open(filename_in) as fin: with open(filename_out, "wb") as fout: for chunk in fin.read(1024): compd_chunk = lzc.compress(chunk.encode("utf-8")) fout.write(comd_chunk) fout.write(lzc.flush())
Сжатый архив составляет 32 байта. В конце мы вызвали метод flush
, который завершает процесс сжатия; созданный объект после этого уже не может использоваться.
Распаковка сжатого архива в Python:
lzd = lzma.LZMADecompressor() with open(filename_out, "rb") as f: data = lzd.decompress(f.read()) print(data[:5].decode("utf-8"))
Высокоуровневые Python-библиотеки сжатия данных
А теперь рассмотрим высокоуровнеые Python-библиотеки сжатия и распаковки данных. Пользователи UNIX-систем чаще всего видят формат tar
и gz
, для работы с ними может пригодиться модуль zlib. У него есть метод open
, который работает так же как и модули выше, поэтому для архивирования в tar
и сжатия в gz
нужно просто выполнить операцию записи.
Вместо того чтобы открывать вложенный цикл для записи порций данных, мы воспользуемся функцией copyfileobj
из модуля shutil. Эта функция по умолчанию копирует данные порциями:
import shutil, gzip filename_in = "data" filename_out = "compressed.tar.gz" with open(filename_in, "rb") as fin: with gzip.open(filename_out, "wb") as fout: shutil.copyfileobj(fin, fout)
Сжатый архив получился равным 1000 байтам из исходного 1 МБ файла.
Преимуществом gzip также является возможность вызова из командной строки через интерпретатор Python. Во многих UNIX-системах программа gzip доступна “из коробки”. А вот для MS Windows очень полезная утилита. Работает она очень просто:
Сжатие (fast или best): $ python3 -m gzip --fast data Распаковка $ python3 -m gzip --decompress compressed.gz
Работаем с zip файлами в Python
Наиболее встречающийся формат для архивов — это zip
. Если вы работаете с ними, тогда вам может пригодиться zipfile. Операции этого модуля производятся через класс ZipFile
.
Поскольку файл zip
представляет собой архив, то туда файлы либо добавляются, либо извлекаются. Итак, добавляются файлы с помощью метода write
:
import zipfile files = ["file1.txt", "file2.txt"] archive = "archive.zip" with zipfile.ZipFile(archive, "w") as zf: for file in files: zf.write(file)
Пароль на сжатый архив ставится с помощью метода setpassword
; пароль должен быть типа bytes
, а не str
, поэтому не забудьте поставить префикс b
:
passwd = b"MyPaSw" with zipfile.ZipFile(archive, "w") as zf: zf.setpassword(passwd)
Для проверки целостности данных в архиве предлагается использовать метод testzip
, который проверит на циклический избыточный код и вернёт None
, если все файлы целы, в противном случае вернёт первый попавшийся испорченный файл:
with zipfile.ZipFile(archive, "r") as zf: crc_test = zf.testzip() if crc_test is not None: print(f"Bad CRC or file headers: {crc_test}")
Для извлечения всех файлов используйте метод extractall
, а для извлечения конкретных файлов — extarct
или open
. Однако первый метод принимает аргументом объект ZipInfo
, который можно получить, например, через метод getinfo
.
with zipfile.ZipFile("archive.zip") as zf: with zf.open("file1.txt") as myfile: print(myfile.read())
Если вам просто нужен список файлов в архиве, то используйте метод namelist
.
И ещё. Модуль zipfile можно вызывать через командную строку. Все опции (их 4) доступны в документации.
Работа с архивами tar в Python
Напоследок разберем модуль tarfile, который очень схож на zipfile. Для добавления файлов в новый архив используется метод add
. А вот для извлечения файлов из архива сначала используется метод getmember
, а затем extract
.
Если нужно ещё и сжать архив, то добавляется суффикс :<format>
:
with tarfile.open("archive.tar.gz", "w:gz") as tar: for file in ["file1.txt", "file2.txt"]: tar.add(file)
Как извлечь файл из архива в Python:
with tarfile.open("archive.tar.gz", "r:gz") as tar: member = tar.getmember("file1.txt") if member.isfile(): tar.extract(member)
А вот если вам требуется добавить файл(ы) в уже существующий сжатый архив, то придется сначала его распаковать (через тот же gzip), поменять режим записи w
на режим добавления a
, а затем снова сжать.
Ещё больше подробностей о работе с файлами, их сжатием, подготовке данных вы узнаете на наших курсах по Python на наших образовательных курсах в лицензированном учебном центре обучения и повышения квалификации руководителей и ИТ-специалистов (менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data) в Москве: