Работа с 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_STORED
allowZip64
, который позволяет разрешить использование расширений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 сериализацию.