Что такое Python zlib
Библиотека Python zlib предоставляет интерфейс Python для библиотеки zlib C, которая представляет собой абстракцию более высокого уровня для алгоритма сжатия без потерь DEFLATE. Формат данных, используемый библиотекой, указан в RFC 1950–1952, который доступен по адресу http://www.ietf.org/rfc/rfc1950.txt .
Формат сжатия zlib можно использовать бесплатно и не защищен никакими патентами, поэтому вы можете безопасно использовать его в коммерческих продуктах. Это формат сжатия без потерь (что означает, что вы не теряете никаких данных между сжатием и распаковкой), и его преимущество заключается в переносимости на разные платформы. Еще одно важное преимущество этого механизма сжатия заключается в том, что он не расширяет данные.
В основном библиотека zlib используется в приложениях, требующих сжатия и распаковки произвольных данных, будь то строка, структурированное содержимое в памяти или файлы.
Наиболее важными функциями, включенными в эту библиотеку, являются сжатие и распаковка. Сжатие и распаковка могут выполняться как разовые операции, так и путем разделения данных на фрагменты, как если бы вы выглядели из потока данных. Оба режима работы описаны в этой статье.
На мой взгляд, одна из лучших особенностей библиотеки zlib заключается в том, что она совместима с форматом / инструментом файла gzip (который также основан на DEFLATE), который является одним из наиболее широко используемых приложений сжатия в системах Unix.
Сжатие
Сжатие строки данных
Библиотека zlib предоставляет нам compress
, которую можно
использовать для сжатия строки данных. Синтаксис этой функции очень
прост, она принимает всего два аргумента:
compress(data, level=-1)
Здесь data
аргумента содержат байты для сжатия, а level
- это целое
число, которое может принимать значения от -1 или от 0 до 9. Этот
параметр определяет уровень сжатия, где уровень 1 является самым быстрым
и дает самый низкий уровень сжатия. . Уровень 9 - самый медленный, но
дает самый высокий уровень сжатия. Значение -1 представляет значение по
умолчанию, то есть уровень 6. Значение по умолчанию имеет баланс между
скоростью и сжатием. Уровень 0 не дает сжатия.
Пример использования compress
для простой строки показан ниже:
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
фигура 1
Если мы изменим уровень на 0 (без сжатия), тогда строка 5 станет:
compressed_data = zlib.compress(data, 0)
И новый результат:
$ python compress_str.py
Original data: Hello world
Compressed data: 7801010b00f4ff48656c6c6f20776f726c6418ab043d
фигура 2
Вы можете заметить некоторые различия, сравнивая выходы при
использовании 0
или 2
для уровня сжатия. Используя уровень 2
мы
получаем строку (в шестнадцатеричном формате) длиной 38, тогда как при
уровне 0
мы получаем шестнадцатеричную строку длиной 44. Эта разница в
длине связана с отсутствием сжатия при использовании уровня 0
.
Если вы не отформатируете строку как шестнадцатеричную, как я сделал в этом примере, и просмотрите выходные данные, вы, вероятно, заметите, что входная строка все еще доступна для чтения даже после "сжатия", хотя в ней есть несколько дополнительных форматирование символов вокруг него.
Сжатие больших потоков данных
Управлять большими потоками данных можно с помощью функции
compressobj()
, которая возвращает объект сжатия. Синтаксис следующий:
compressobj(level=-1, method=DEFLATED, wbits=15, memLevel=8, strategy=Z_DEFAULT_STRATEGY[, zdict])
Основное различие между аргументами этой функции и функцией compress()
заключается (помимо data
) в wbits
, который управляет размером
окна, а также тем, включены ли в вывод заголовок и трейлер.
Возможные значения для wbits
:
Значение Логарифм размера окна Выход
От +9 до +15 База 2 Включает заголовок и трейлер zlib От -9 до -15 Абсолютное значение wbits Без заголовка и трейлера От +25 до +31 Младшие 4 бита значения Включает заголовок gzip и конечную контрольную сумму
Таблица 1
method
представляет используемый алгоритм сжатия. В настоящее время
единственное возможное значение - DEFLATED
, единственный метод,
определенный в RFC 1950. strategy
относится к настройке сжатия. Если
вы действительно не знаете, что делаете, я бы рекомендовал не
использовать его и просто использовать значение по умолчанию.
В следующем коде показано, как использовать функцию 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
Рисунок 3
Как видно из рисунка выше, фраза «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%
Рисунок 4
Как видим, файл сжался на 13%.
Единственное различие между этим примером и нашим первым - это источник
данных. Однако я думаю, что это важно показать, чтобы вы могли понять,
какие данные можно сжимать, будь то просто строка ASCII или данные
двоичного изображения. Просто прочтите свои данные из файла, как обычно,
и вызовите метод compress
Сохранение сжатых данных в файл
Сжатые данные также можно сохранить в файл для дальнейшего использования. В приведенном ниже примере показано, как сохранить сжатый текст в файл:
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" при открытии в нашем текстовом редакторе выглядит следующим образом:
{.ezlazyload .img-responsive}
Рисунок 5.
Декомпрессия
Распаковка строки данных
Сжатую строку данных можно легко распаковать с помощью функции
decompress()
. Синтаксис следующий:
decompress(data, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE)
Эта функция распаковывает байты в аргументе data
wbits
может
использоваться для управления размером буфера истории. Значение по
умолчанию соответствует наибольшему размеру окна. Он также просит
включить заголовок и трейлер сжатого файла. Возможные значения:
Значение Логарифм размера окна Вход
От +8 до +15 База 2 Включает заголовок и трейлер zlib От -8 до -15 Абсолютное значение wbits Необработанный поток без заголовка и трейлера От +24 до +31 = 16 + (от 8 до 15) Младшие 4 бита значения Включает заголовок и трейлер gzip От +40 до +47 = 32 + (от 8 до 15) Младшие 4 бита значения формат zlib или gzip
Таблица 2
Начальное значение размера буфера указывается в аргументе 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
Рисунок 5.
Распаковка больших потоков данных
Распаковка больших потоков данных может потребовать управления памятью
из-за размера или источника ваших данных. Возможно, вы не сможете
использовать всю доступную память для этой задачи (или у вас
недостаточно памяти), поэтому метод decompressobj()
позволяет
разделить поток данных на несколько частей, которые вы можно распаковать
отдельно.
Синтаксис функции decompressobj()
следующий:
decompressobj(wbits=15[, zdict])
Эта функция возвращает объект декомпрессии, который вы используете для
распаковки отдельных данных. Аргумент wbits имеет те же характеристики,
что и в ранее wbits
decompress()
В следующем коде показано, как распаковать большой поток данных,
хранящийся в файле. Во-первых, программа создает файл с именем
«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
Рисунок 6
Распаковка данных из файла
Сжатые данные, содержащиеся в файле, можно легко распаковать, как вы
видели в предыдущих примерах. Этот пример очень похож на предыдущий в
том, что мы распаковываем данные, происходящие из файла, за исключением
того, что в этом случае мы возвращаемся к использованию одноразового
decompress
, который распаковывает данные за один вызов метода. . Это
полезно, когда ваши данные достаточно малы, чтобы легко поместиться в
памяти.
Это видно из следующего примера:
import zlib
compressed_data = open('compressed.dat', 'rb').read()
decompressed_data = zlib.decompress(compressed_data)
print(decompressed_data)
Вышеупомянутая программа открывает файл compressed.dat, созданный в предыдущем примере, который содержит сжатую строку «Hello world».
В этом примере, как только сжатые данные извлечены и сохранены в
переменной compressed_data
, программа распаковывает поток и
показывает результат на экране. Поскольку файл содержит небольшой объем
данных, в примере используется функция decompress()
Однако, как
показывает предыдущий пример, мы также можем распаковать данные с
помощью функции decompressobj()
.
После запуска программы получаем следующий результат:
$ python decompress_file.py
Hello world
Рисунок 7
Заключение
Библиотека Python zlib предоставляет нам полезный набор функций для
сжатия файлов с использованием формата zlib. Обычно используются функции
compress()
и decompress()
. Однако при наличии ограничений памяти
доступны функции compressobj()
и decompressobj()
для обеспечения
большей гибкости за счет поддержки сжатия / распаковки потоков данных.
Эти функции помогают разделить данные на более мелкие и более
управляемые фрагменты, которые можно сжимать или распаковывать с помощью
compress()
и decompress()
соответственно.
Имейте в виду, что библиотека zlib также имеет гораздо больше функций, чем то, что мы смогли охватить в этой статье. Например, вы можете использовать zlib для вычисления контрольной суммы некоторых данных, чтобы проверить их целостность при распаковке. Для получения дополнительной информации о дополнительных функциях, подобных этой, ознакомьтесь с официальной документацией .