Библиотека zlib предоставляет интерфейс Python для библиотеки zlib C, которая представляет собой абстракцию более высокого уровня для алгоритма сжатия без потерь DEFLATE.
Формат сжатия zlib можно использовать бесплатно и не защищен никакими патентами, поэтому вы можете безопасно использовать его в коммерческих продуктах. Это формат сжатия без потерь (что означает, что вы не теряете никаких данных между сжатием и распаковкой), и его преимущество заключается в переносимости на разные платформы. Еще одно важное преимущество этого механизма сжатия заключается в том, что он не расширяет данные.
В основном библиотека zlib используется в приложениях, требующих сжатия и распаковки произвольных данных, будь то строка, структурированное содержимое в памяти или файлы.
Наиболее важными функциями, включенными в эту библиотеку, являются сжатие и распаковка. Сжатие и распаковка могут выполняться как разовые операции, так и путем разделения данных на фрагменты, как если бы вы выглядели из потока данных. Оба режима работы описаны в этой статье.
На мой взгляд, одна из лучших особенностей библиотеки zlib заключается в том, что она совместима с форматом / инструментом файла gzip (который также основан на DEFLATE), который является одним из наиболее широко используемых приложений сжатия в системах Unix.
Сжатие: синтаксис и пример
Библиотека zlib предоставляет нам функцию сжатия, которую можно использовать для сжатия строки данных. Синтаксис этой функции очень прост, она принимает всего два аргумента:
compress(data, level=-1)
Здесь данные аргумента содержат байты для сжатия, а уровень – это целое число, которое может принимать значения от -1 или от 0 до 9. Этот параметр определяет уровень сжатия, где уровень 1 является самым быстрым и дает самый низкий уровень сжатия.
Уровень 9 – самый медленный, но дает самый высокий уровень сжатия. Значение -1 представляет значение по умолчанию, то есть уровень 6. Значение по умолчанию имеет баланс между скоростью и сжатием. Уровень 0 не дает сжатия.
Пример использования метода сжатия для простой строки показан ниже:
import zlib
import binascii
data = 'Hello world'
compressed_data = zlib.compress(data, 2)
print('Original data: ' + data)
print('Compressed data: ' + binascii.hexlify(compressed_data))
И вот результат:
$ python compress_str.py Original data: Hello world Compressed data: 785ef348cdc9c95728cf2fca49010018ab043d
Если мы изменим уровень на 0 (без сжатия), тогда строка 5 станет:
compressed_data = zlib.compress(data, 0)
И новый результат:
$ python compress_str.py Original data: Hello world Compressed data: 7801010b00f4ff48656c6c6f20776f726c6418ab043d
Вы можете заметить некоторые различия, сравнивая выходы при использовании 0 или 2 для уровня сжатия. Используя уровень 2, мы получаем строку (отформатированную в шестнадцатеричном формате) длиной 38, тогда как при уровне 0 мы получаем шестнадцатеричную строку длиной 44. Эта разница в длине связана с отсутствием сжатия при использовании уровня 0.
Если вы не отформатируете строку как шестнадцатеричную, как я сделал в этом примере, и просмотрите выходные данные, вы, вероятно, заметите, что входная строка все еще доступна для чтения даже после «сжатия», хотя в ней есть несколько дополнительных форматирование символов вокруг него.
Сжатие больших потоков данных
Управлять большими потоками данных можно с помощью функции compressobj(), которая возвращает объект сжатия. Синтаксис следующий:
compressobj(level=-1, method=DEFLATED, wbits=15, memLevel=8, strategy=Z_DEFAULT_STRATEGY[, zdict])
Основное различие между аргументами этой функции и функцией compress() заключается (помимо параметра данных) в аргументе wbits, который управляет размером окна, а также тем, включены ли в вывод заголовок и трейлер.
Возможные значения для wbits:
| Ценить | Логарифм размера окна | Выход |
|---|---|---|
| От +9 до +15 | База 2 | Включает заголовок и трейлер zlib |
| От -9 до -15 | Абсолютное значение wbits | Без заголовка и трейлера |
| От +25 до +31 | Младшие 4 бита значения | Включает заголовок gzip и конечную контрольную сумму |
Аргумент метода представляет используемый алгоритм сжатия. В настоящее время единственное возможное значение – DEFLATED, единственный метод, определенный в RFC 1950. Аргумент стратегии относится к настройке сжатия. Если вы действительно не знаете, что делаете, я бы рекомендовал не использовать его и просто использовать значение по умолчанию.
В следующем коде показано, как использовать функцию compressobj():
import zlib
import binascii
data = 'Hello world'
compress = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -15)
compressed_data = compress.compress(data)
compressed_data += compress.flush()
print('Original: ' + data)
print('Compressed data: ' + binascii.hexlify(compressed_data))
После запуска этого кода результат будет следующим:
$ python compress_obj.py Original: Hello world Compressed data: f348cdc9c95728cf2fca490100
Как видно из примера выше, фраза «Hello world» сжата. Обычно этот метод используется для сжатия потоков данных, которые не помещаются в память сразу. Хотя в этом примере не очень большой поток данных, он служит для демонстрации механизма работы функции compressobj().
Вы также можете увидеть, как это будет полезно в более крупном приложении, в котором вы можете настроить сжатие, а затем передать объект сжатия другим методам или модулям. Затем это можно использовать для последовательного сжатия порций данных.
Вы также можете увидеть, как это будет полезно в скрипте, когда у вас есть поток данных для сжатия. Вместо того, чтобы накапливать все данные в памяти, вы можете просто вызвать compress.compress (data) и compress.flush() для своего фрагмента данных, а затем перейти к следующему фрагменту, оставив предыдущий для очистки вывоз мусора.
Сжатие файла
Мы также можем использовать функцию compress() для сжатия данных в файле. Синтаксис такой же, как в первом примере.
В приведенном ниже примере мы сжимаем файл изображения PNG с именем «logo.png» (который, я должен отметить, уже является сжатой версией исходного необработанного изображения).
Пример кода выглядит следующим образом:
import zlib
original_data = open('logo.png', 'rb').read()
compressed_data = zlib.compress(original_data, zlib.Z_BEST_COMPRESSION)
compress_ratio = (float(len(original_data)) - float(len(compressed_data))) / float(len(original_data))
print('Compressed: %d%%' % (100.0 * compress_ratio))
В приведенном выше коде строка zlib.compress (…) использует константу Z_BEST_COMPRESSION, которая, как следует из названия, дает нам лучший уровень сжатия, который может предложить этот алгоритм. Следующая строка затем вычисляет уровень сжатия на основе отношения длины сжатых данных к длине исходных данных.
Результат такой:
$ python compress_file.py Compressed: 13%
Как видим, файл сжался на 13%.
Единственное различие между этим примером и нашим первым – это источник данных. Однако я думаю, что это важно показать, чтобы вы могли понять, какие данные можно сжимать, будь то просто строка ASCII или данные двоичного изображения. Просто прочтите свои данные из файла, как обычно, и вызовите метод сжатия.
Сохранение сжатых данных в файл
Сжатые данные также можно сохранить в файл для дальнейшего использования. В приведенном ниже примере показано, как сохранить сжатый текст в файл:
import zlib
my_data = 'Hello world'
compressed_data = zlib.compress(my_data, 2)
f = open('outfile.txt', 'w')
f.write(compressed_data)
f.close()
В приведенном выше примере сжимается наша простая строка «Hello world» и сохраняются сжатые данные в файл с именем «outfile.txt». Файл «outfile.txt» при открытии в нашем текстовом редакторе выглядит следующим образом:

Декомпрессия
Сжатую строку данных можно легко распаковать с помощью функции декомпрессии(). Синтаксис следующий:
decompress(data, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE)
Эта функция распаковывает байты в аргументе данных. Аргумент wbits может использоваться для управления размером буфера истории. Значение по умолчанию соответствует наибольшему размеру окна. Он также просит включить заголовок и трейлер сжатого файла. Возможные значения:
| Ценить | Логарифм размера окна | Вход |
|---|---|---|
| От +8 до +15 | База 2 | Включает заголовок и трейлер zlib |
| От -8 до -15 | Абсолютное значение wbits | Необработанный поток без заголовка и трейлера |
| От +24 до +31 = 16 + (от 8 до 15) | Младшие 4 бита значения | Включает заголовок и трейлер gzip |
| От +40 до +47 = 32 + (от 8 до 15) | Младшие 4 бита значения | формат zlib или gzip |
Начальное значение размера буфера указывается в аргументе bufsize. Однако важным аспектом этого параметра является то, что он не обязательно должен быть точным, потому что, если потребуется дополнительный размер буфера, он будет автоматически увеличен.
В следующем примере показано, как распаковать строку данных, сжатую в нашем предыдущем примере:
import zlib
data = 'Hello world'
compressed_data = zlib.compress(data, 2)
decompressed_data = zlib.decompress(compressed_data)
print('Decompressed data: ' + decompressed_data)
Результат такой:
$ python decompress_str.py Decompressed data: Hello world
Распаковка больших потоков данных
Распаковка больших потоков данных может потребовать управления памятью из-за размера или источника ваших данных. Возможно, вы не сможете использовать всю доступную память для этой задачи (или у вас недостаточно памяти), поэтому метод decopressobj() позволяет разделить поток данных на несколько частей, которые вы можно распаковать отдельно.
Синтаксис функции decopressobj() следующий:
decompressobj(wbits=15[, zdict])
Эта функция возвращает объект декомпрессии, который вы используете для распаковки отдельных данных. Аргумент wbits имеет те же характеристики, что и в ранее описанной функции decopress().
В следующем коде показано, как распаковать большой поток данных, хранящийся в файле. Во-первых, программа создает файл с именем «outfile.txt», который содержит сжатые данные. Обратите внимание, что данные сжимаются с использованием значения wbits, равного +15. Это гарантирует создание заголовка и трейлера в данных.
Затем файл распаковывается с использованием фрагментов данных. Опять же, в этом примере файл не содержит большого количества данных, но, тем не менее, он служит цели объяснения концепции буфера.
Код выглядит следующим образом:
import zlib
data = 'Hello world'
compress = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, +15)
compressed_data = compress.compress(data)
compressed_data += compress.flush()
print('Original: ' + data)
print('Compressed data: ' + compressed_data)
f = open('compressed.dat', 'w')
f.write(compressed_data)
f.close()
CHUNKSIZE = 1024
data2 = zlib.decompressobj()
my_file = open('compressed.dat', 'rb')
buf = my_file.read(CHUNKSIZE)
# Decompress stream chunks
while buf:
decompressed_data = data2.decompress(buf)
buf = my_file.read(CHUNKSIZE)
decompressed_data += data2.flush()
print('Decompressed data: ' + decompressed_data)
my_file.close()
После запуска приведенного выше кода мы получаем следующие результаты:
$ python decompress_data.py Original: Hello world Compressed data: x??H???W(?/?I?= Decompressed data: Hello world
Распаковка данных из файла
Сжатые данные, содержащиеся в файле, можно легко распаковать, как вы видели в предыдущих примерах. Этот пример очень похож на предыдущий в том, что мы распаковываем данные, происходящие из файла, за исключением того, что в этом случае мы возвращаемся к использованию одноразового метода распаковки, который распаковывает данные за один вызов метода. Это полезно, когда ваши данные достаточно малы, чтобы легко поместиться в памяти.
Это видно из следующего примера:
import zlib
compressed_data = open('compressed.dat', 'rb').read()
decompressed_data = zlib.decompress(compressed_data)
print(decompressed_data)
Вышеупомянутая программа открывает файл compressed.dat, созданный в предыдущем примере, который содержит сжатую строку «Hello world».
В этом примере, как только сжатые данные извлечены и сохранены в переменной compressed_data, программа распаковывает поток и показывает результат на экране. Поскольку файл содержит небольшой объем данных, в примере используется функция декомпрессии(). Однако, как показывает предыдущий пример, мы также можем распаковать данные с помощью функции decopressobj().
После запуска программы получаем следующий результат:
$ python decompress_file.py Hello world
Заключение
Библиотека zlib в Python предоставляет нам полезный набор функций для сжатия файлов с использованием формата zlib. Обычно используются функции compress() и decopress(). Однако при наличии ограничений памяти доступны функции compressobj() и decopressobj() для обеспечения большей гибкости за счет поддержки сжатия или распаковки потоков данных.
Эти функции помогают разделить данные на более мелкие и более управляемые фрагменты, которые можно сжимать или распаковывать с помощью функций compress() и decompression() соответственно.