Учебное пособие по библиотеке Python zlib

Что такое Python zlib Библиотека Python zlib предоставляет интерфейс Python для библиотеки zlib [https://en.wikipedia.org/wiki/Zlib] C, которая является абстракцией более высокого уровня для DEFLATE [https: // en. wikipedia.org/wiki/DEFLATE] алгоритм сжатия без потерь. Формат данных, используемый библиотекой, указан в RFC 1950–1952, который доступен по адресу http://www.ietf.org/rfc/rfc1950.txt. Формат сжатия zlib можно использовать бесплатно и не защищен никакими патентами, поэтому вы можете безопасно использовать его в совместной работе.

Что такое 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 для вычисления контрольной суммы некоторых данных, чтобы проверить их целостность при распаковке. Для получения дополнительной информации о дополнительных функциях, подобных этой, ознакомьтесь с официальной документацией .

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus