Библиотека zlib в Python

Библиотека 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» при открытии в нашем текстовом редакторе выглядит следующим образом:

Файл "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() соответственно.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *