Работа с zip и pkl файлами в Python
Управление файлами формата zip, pkl в языке программирования Python
Формат zip
zip — это формат сжатия без потерь: после распаковки данные будут такими же, как перед сжатием. Алгоритм ищет избыточности в исходных данных и эффективнее представляет информацию.
Формат zip обладает следующими преимуществами:
- является полностью открытым
- является одним из самых популярных (большинство архивов в Internet – это архивы zip)
- является очень быстрым
Сначала разберёмся, как считать степень сжатия файла — коэффициент K, определяемый как отношение объема сжатого файла к объему исходного файла, выраженным в процентах:
$$ K = \frac{V_{c}} {V_{o}} * 100\% $$
Степень сжатия зависит от используемой программы, метода сжатия и типа исходного файла. Наиболее хорошо сжимаются файлы графических образов, текстовые файлы и файлы данных, для которых степень сжатия может достигать 5–40%, меньше сжимаются файлы исполняемых программ и загрузочных модулей — 60–90%. Почти не сжимаются архивные файлы.
Модуль zipfile
В этом конспекте будет рассмотрен объекты ZipFile и ZipInfo, однако модуль zipfile содержит и другие классы.
Для использования: from zipfile import ZipFile
Методы ZipFile
printdir()— выводит таблицу с информацией о содержимом архива: полные названия файлов с указанием даты изменения и размера в байтах.
|
|
|
|
ZipFile мы также можем передать необязательный аргумент mode, который задает режим работы (по аналогии с обычными файлами): r — чтение, w — запись в новый файл, a — запись в конец существующего файлаinfolist()— позволяет получить информацию о файлах из архива в виде списка объектовZipInfo, которые содержат дополнительную информацию о каждом файле:file_size,compress_size,filename,date_timeи другие.
|
|
|
|
Метод is_dir() объекта ZipInfo нужен, чтобы проверить, является ли этот объект файлом (возвращает False) или папкой (True).
namelist()— возвращает список названий файлов и директорий, содержащихся в архиве.
|
|
|
|
getinfo()— в отличие от методаinfolist(), который позволяет получить информацию о всех файлах из архива в виде списка специальных объектов (типZipInfo), методgetinfo()позволяет получить информацию о конкретном файле по его имени в архиве.
|
|
|
|
При создании объекта ZipFile мы также можем передать еще два необязательных аргумента:
compression, который определяет метод сжатия, который должен использоваться при записи в архив. Он принимает одно из значений:ZIP_STORED, ZIP_DEFLATED, ZIP_BZIP2, ZIP_LZMA. По умолчанию используется значениеcompression=ZIP_STOREDallowZip64, который позволяет разрешить использование расширенийzip64, которые дают возможность создавать архивы размером больше 4 гигабайт. По умолчанию равенallowZip64=True
Для того чтобы проверить является ли некоторый файл zip архивом, используется функция zipfile.is_zipfile(), которая принимает на вход путь к файлу (или сам файловый объект) и возвращает значение True, если указанный файл является zip архивом, или False в противном случае.
Работы с конкретными файлами архива
Откроем отдельный файла из архива:
|
|
|
|
Метод ZipFile.open() открывает файл в бинарном виде, поэтому перед выводом стоит символ b, а значит перед нами бинарная строка. Чтобы преобразовать байты в строку, воспользуемся методом decode() с указанием кодировки ('utf-8'):
|
|
|
|
Запись в архив
Чтобы записать файл в архив, нужно как минимум открыть его для записи (mode='w' — для записи с удалением уже имеющегося содержимого; или mode='a' — для записи в конец, сохраняя содержимое). Далее, используем метод write():
|
|
FileNotFoundErrorМетод write() может принимать еще один строковый аргумент, задающий новое имя файла в архиве.
Извлечение содержимого
Если требуется извлечь отдельные файлы, то используется метод extract(), он принимает два аргумента: название файла и путь, по которому требуется извлечь файл. Если путь не указывать, то файл будет извлечен в папку, где находится файл с программой.
Следующий код извлекает файлы из архива test.zip
|
|
Если требуется извлечь все содержимое архива, то используется метод extractall(), он принимает в качестве аргумента путь, по которому требуется извлечь все файлы. Если путь не указывать, то файл будет извлечен в папку, где находится файл с программой.
Сериализация и десериализация
Преобразование переменных программы (Python-объектов) в формат для хранения называется «сериализацией», а обратное преобразование — «десериализацией».
Сериализация объектов часто используется для:
- сохранения состояния программы (то есть некоторых её объектов) между запусками
- передачи данных между различными программами (например, по сети)
Главная идея состоит в том, что сериализованный формат — набор байт или строка, которую можно легко сохранить на диск или передать другой программе, в отличие от самого объекта. А значит, задача сохранения объекта/группы объектов при этом сводится к простой задаче сохранения набора байт или строки.
Модуль pickle
Помимо сериализации в формат json мы также можем использовать бинарную сериализацию, то есть сериализацию в байты. Для этого в Python используется модуль pickle. Интерфейс взаимодействия с модулем pickle абсолютно такой же, как и для модуля json. Мы будем использовать четыре основных функции: dump(), dumps(), load(), loads().
pickle сериализует и десериализует данные быстрее чем модуль json.Модуль pickle может сериализовывать:
- Все встроенные типы данных (
bool, int, float, complex, str, None); - Списки, кортежи, словари и множества, содержащие любую комбинацию встроенных типов данных (но не генераторы);
- Списки, кортежи, словари и множества, содержащие любую комбинацию списков, кортежей, словарей и множеств;
- Функции (но не
lambda-функции), классы и экземпляры классов.
Разберём функции модуля:
- Функция
dump()модуляpickleпринимает сериализуемый Python объект, сериализует его в бинарный, Python-зависимый формат, используя протоколpickle, и сохраняет его в открытый для записи бинарный файл.
Следующий код создает файл file.pkl, содержащий бинарное представление объекта obj:
|
|
- Функция
dumps()выполняет такую же сериализацию, как и функцияdump(). Но вместо того чтобы сохранять сериализованные данные в открытый для записи бинарный файл, она просто возвращает эти сериализованные данные.
|
|
|
|
Поскольку протокол pickle использует бинарный формат данных, функция dumps() возвращает объект типа bytes.
bytes — это неизменяемые последовательности отдельных байтов. Синтаксис для байтовых литералов в основном такой же, как и для строковых литералов, за исключением того, что добавляется префикс b.- Функция
load()принимает файловый объект, читает из него сериализованные данные, десериализует их в Python-объект и возвращает полученный Python-объект.
|
|
|
|
- Функция
loads()выполняет такую же десериализацию, как и функцияload(). Но вместо того чтобы принимать файловый объект, она принимает объект типаbytes, содержащий сериализованные данные.
|
|
|
|
Интересно то, что объекты obj и new_obj имеют одинаковое содержимое, но по сути не идентичны.
pickle зависит от Python и не совместим с другими языками программирования. Если необходима совместимость с другими языками программирования, то следует использовать JSON сериализацию.
cloudtips