Сообщить об ошибке.

Объект ZipFile модуля zipfile в Python

Использование объекта ZipFile с описанием

В данном разделе рассмотрены методы объекта ZipFile с их подробным описанием и примерами. Объект ZipFile получается в результате создания экземпляра класса 'zipfile.ZipFile()'.

Содержание:


ZipFile.close():

Метод ZipFile.close() закрывает файл архива. Необходимо вызвать этот метод перед выходом из программы, иначе не вся информация будет записана или используйте менеджер контекста.

myzip = zipfile.ZipFile('spam.zip', 'w')
myzip.write('eggs.txt')
myzip.close()

# эквивалентно

with zipfile.ZipFile('spam.zip', 'w') as myzip:
    myzip.write('eggs.txt')

ZipFile.getinfo(name):

Метод ZipFile.getinfo() возвращает объект zipfile.ZipInfo() с информацией для элемента архива с именем name.

Вызов метода ZipFile.getinfo() для несуществующего имени элемента архива вызовет исключение KeyError.

import zipfile, os

with zipfile.ZipFile('test.zip') as zf:
    for name in zf.namelist():
        info = zf.getinfo(name)
        print(f"{os.path.basename(info.filename)},\t\
              {info.compress_size},\t{info.file_size}")

# script-add.sql, 851,    3102
# Script-1.sql,   280,    1371
# Script-2.sql,   431,    1130
# Script-3.sql,   52,     50
# Script-4.sql,   405,    1163
# Script-5.sql,   893,    2687
# procedure.sql,  998,    3394

ZipFile.infolist():

Метод ZipFile.infolist() возвращает список, содержащий объект zipfile.ZipInfo() для каждого члена архива.

Объекты находятся в том же порядке, что и в реальном ZIP-файле на диске.

import zipfile, os

with zipfile.ZipFile('test.zip') as zf:
    for info in zf.infolist():
        print(f"{os.path.basename(info.filename)},\t\
              {info.compress_size},\t{info.file_size}")

# script-add.sql, 851,    3102
# Script-1.sql,   280,    1371
# Script-2.sql,   431,    1130
# Script-3.sql,   52,     50
# Script-4.sql,   405,    1163
# Script-5.sql,   893,    2687
# procedure.sql,  998,    3394

ZipFile.namelist():

Метод ZipFile.namelist() возвращает список членов архива по имени.

import zipfile

with zipfile.ZipFile('test.zip') as zf:
    for name in zf.namelist():
        print(name)

# script-add.sql
# home/docs-python/script/sql-script/Script-1.sql
# home/docs-python/script/sql-script/Script-2.sql
# home/docs-python/script/sql-script/Script-3.sql
# home/docs-python/script/sql-script/Script-4.sql
# home/docs-python/script/sql-script/Script-5.sql
# home/docs-python/script/sql-script/procedure.sql

ZipFile.open(name, mode='r', pwd=None, *, force_zip64=False):

Метод ZipFile.open() предоставляет доступ к элементу архива в виде двоичного файлового объекта.

  • Аргумент name может быть либо именем файла в архиве, либо объектом zipfile.ZipInfo().
  • Аргумент mode, если он включен, должен иметь значение 'r' (по умолчанию) или 'w'.
  • Аргумент pwd - это пароль, используемый для расшифровки зашифрованных ZIP-файлов.

Метод ZipFile.open() является менеджером контекста и поэтому поддерживает оператор with:

with ZipFile('spam.zip') as myzip:
    with myzip.open('eggs.txt') as myfile:
        print(myfile.read())

В режиме mode='r' файлоподобный объект ZipExtFile доступен только для чтения и предоставляет следующие методы: read(), readline(), readlines(), seek(), tell(), __iter__(), __next__(). Эти объекты могут работать независимо от объектаZipFile`.

В режиме mode='w'возвращается дескриптор доступного для записи файла, который поддерживает метод write(). Когда дескриптор доступного для записи файла открыт, попытка чтения или записи других файлов в ZIP-архиве вызовет ошибку ValueError.

При записи файла, если размер файла заранее неизвестен, но может превышать 2 ГБ, то передайте force_zip64=True для поддержки больших файлов. Если размер файла известен заранее, то создавайте объект zipfile.ZipInfo() с установленным аргументом file_size и используйте его в качестве параметра имени.

import zipfile

text = 'Это новый текстовый файл в архиве.'

# Добавим в архив 'test.zip' файл 'ReadMe.txt'
# с текстом внутри 'text'
with zipfile.ZipFile('test.zip', mode='a') as zf:
    with zf.open('ReadMe.txt', mode='w') as fp:
        fp.write(text.encode('utf-8'))

# смотрим результат добавления
with zipfile.ZipFile('test.zip') as zf:
    for name in zf.namelist():
        print(name)

# script-add.sql
# home/docs-python/script/sql-script/Script-1.sql
# home/docs-python/script/sql-script/Script-2.sql
# home/docs-python/script/sql-script/Script-3.sql
# home/docs-python/script/sql-script/Script-4.sql
# home/docs-python/script/sql-script/Script-5.sql
# home/docs-python/script/sql-script/procedure.sql
# ReadMe.txt

# теперь прочитаем добавленный файл
# прямо из архива, не извлекая его
with zipfile.ZipFile('test.zip') as zf:
    with zf.open('ReadMe.txt') as fp:
        text = fp.read()
        print(text.decode('utf-8'))

# Это новый текстовый файл в архиве.

Примечание. Методы ZipFile.open(), ZipFile.read() и ZipFile.extract() могут принимать в качестве имени файла объект zipfile.ZipInfo(). Вы оцените это при попытке прочитать ZIP-файл, содержащий элементы архива с повторяющимися именами.

ZipFile.extract(member, path=None, pwd=None):

Метод ZipFile.extract() извлекает элемент архива member в текущий рабочий каталог.

  • Аргумент member должен быть полным именем или объектом zipfile.ZipInfo(). Информация о его файле извлекается максимально точно.
  • Аргумент пути path указывает другой каталог для извлечения.
  • Аргумент pwd - пароль, используемый для зашифрованных файлов.

Метод ZipFile.extract() возвращает созданный нормализованный путь (каталог или новый файл).

import zipfile, fnmatch, glob

# директория для извлечения
extract_dir = 'extract_dir'
# паттерн для извлечения файлов
file_pattern = '*-[0-9].sql'

with zipfile.ZipFile('test.zip') as zf:
    for file in zf.infolist():
        # выбираем файлы для извлечения по 'file_pattern'
        if fnmatch.fnmatch(file.filename, file_pattern):
            zf.extract(file.filename, extract_dir)

>>> for file in glob.glob(extract_dir + '/**', recursive=True):
...    print(file)
...
# extract_dir/home/docs-python/script/sql-script/Script-5.sql
# extract_dir/home/docs-python/script/sql-script/Script-1.sql
# extract_dir/home/docs-python/script/sql-script/Script-3.sql
# extract_dir/home/docs-python/script/sql-script/Script-2.sql
# extract_dir/home/docs-python/script/sql-script/Script-4.sql

Примечание. Если имя файла архива является абсолютным путем, разделяющая точка диска drive/UNC и начальная (обратная) косая черта будут удалены, например: ////foo/bar становится foo/bar в Unix, а C:\foo\bar становится foo\bar в Windows. И все компоненты '..' в имени файла элемента архива будут удалены, например: ../../foo../../ba..r становится foo../ba..r. В Windows недопустимые символы :, <, >, |, ", ? и * заменяются подчеркиванием _.

ZipFile.extractall(path=None, members=None, pwd=None):

Метод ZipFile.extractall() извлекает все элементы архива в текущий рабочий каталог.

  • Аргумент пути path указывает другой каталог для извлечения.
  • Аргумент members не обязателен и должен быть подмножеством списка, возвращаемого методом ZipFile.namelist().
  • Аргумент pwd - пароль, используемый для зашифрованных файлов.
import zipfile, glob

extract_dir = 'extract_dir'
with zipfile.ZipFile('test.zip') as zf:
    zf.extractall(extract_dir)

>>> for file in glob.glob(extract_dir + '/**', recursive=True):
...    print(file)
...
# extract_dir/home/docs-python/script/sql-script/Script-5.sql
# extract_dir/home/docs-python/script/sql-script/Script-1.sql
# extract_dir/home/docs-python/script/sql-script/Script-3.sql
# extract_dir/home/docs-python/script/sql-script/procedure.sql
# extract_dir/home/docs-python/script/sql-script/Script-2.sql
# extract_dir/home/docs-python/script/sql-script/Script-4.sql
# extract_dir/script-add.sql
# extract_dir/ReadMe.txt

Предупреждение.
Никогда не извлекайте архивы из ненадежных источников без предварительной проверки. Имена файлов или каталогов внутри архива архива могут иметь абсолютные имена файлов, начинающиеся с '/' или имена файлов с двумя точками '..'. Модуль zipfile будет пытается исправить это. Смотрите примечание метода ZipFile.extract().

ZipFile.printdir():

Метод ZipFile.printdir() печатает оглавление архива в sys.stdout.

import zipfile, glob

with zipfile.ZipFile('test.zip') as zf:
    zf.printdir()

# File Name                                             Modified             Size
# script-add.sql                                 2019-09-14 08:07:28         3102
# home/docs-python/script/sql-script/Script-1.sql 2019-09-14 08:06:38         1371
# home/docs-python/script/sql-script/Script-2.sql 2019-09-14 08:06:30         1130
# home/docs-python/script/sql-script/Script-3.sql 2019-09-14 08:00:46           50
# home/docs-python/script/sql-script/Script-4.sql 2019-09-14 08:06:30         1163
# home/docs-python/script/sql-script/Script-5.sql 2019-09-14 08:07:18         2687
# home/docs-python/script/sql-script/procedure.sql 2019-09-14 08:07:34         3394
# ReadMe.txt                                    2019-09-14 00:00:00           30

ZipFile.setpassword(pwd):

Метод ZipFile.setpassword() устанавливает pwd в качестве пароля по умолчанию для извлечения зашифрованных файлов.

ZipFile.read(name, pwd=None):

Метод ZipFile.read() возвращает байты прочитанный из файла в архиве с именем name.

  • Аргумент name - строка с полным именем файла в архиве или объект zipfile.ZipInfo(). Архив должен быть открыт для чтения или добавления.
  • Аргумент pwd - это пароль, используемый для зашифрованных файлов и если он указан, он переопределит пароль по умолчанию, установленный с помощью метода ZipFile.setpassword().

Вызов ZipFile.read() для экземпляра класса zipfile.ZipFile, который использует метод сжатия, отличный от ZIP_STORED, ZIP_DEFLATED, ZIP_BZIP2 или ZIP_LZMA, вызовет исключение NotImplementedError. Также будет возникать ошибка, если соответствующий модуль сжатия недоступен.

import zipfile

with zipfile.ZipFile('test.zip') as zf:
    for file in zf.infolist():
        if 'ReadMe' in file.filename:
            byte_text = zf.read(file)
            print(byte_text.decode('utf-8'))

# Это новый текстовый файл в архиве.

ZipFile.testzip():

Метод ZipFile.testzip() читает все файлы в архиве и проверяет их CRC и заголовки файлов. Возвращает имя первого неверного/битого файла или если все "путем", то возвращает None.

import zipfile

with zipfile.ZipFile('test.zip') as zf:
    ok = zf.testzip()
    print('It`s OK!') if ok is None else print(f'{ok} is fail.')

# It`s OK!

ZipFile.write(filename, arcname=None, compress_type=None, compresslevel=None):

Метод ZipFile.write() добавляет файл с именем filename в архив, присвоив ему имя в архиве arcname, по умолчанию это будет то же самое, что и filename, но без буквы диска и с удаленными начальными разделителями пути.

Если задан аргумент compress_type, то он переопределяет значение этого параметра, заданное при создании экземпляра класса zipfile.ZipFile для добавления в архив нового элемента. Аналогично, если задан аргумент compresslevel, то он переопределит конструктор. Архив должен быть открыт в режиме 'w', 'x' или 'a'.

import zipfile, os, glob

path = '/home/docs-python/script/'
# составим список добавляемых файлов в архив
file_dir = glob.glob(path+'**', recursive=True)

with zipfile.ZipFile('test.zip', mode='w', \
                     compression=zipfile.ZIP_DEFLATED) as zf:
    for file in file_dir:
        zf.write(file)

>>> os.system('file test.zip')
# test.zip: Zip archive data, at least v2.0 to extract

Примечания:

  • В стандарте ZIP-файлов исторически не указывалась кодировка метаданных, но настоятельно рекомендовалась CP437 (исходная кодировка IBM PC) для совместимости. Последние версии позволяют использовать только UTF-8. В этом модуле, для записи имен элементов будет автоматически использоваться UTF-8, если они содержат какие-либо символы, отличные от ASCII. Невозможно записать имена членов в какой-либо другой кодировке, кроме ASCII или UTF-8.
  • Имена архивов должны относиться к корню архива, то есть они не должны начинаться с разделителя пути.
  • Если arcname или имя файла, если arcname не указано содержит нулевой байт, то имя файла в архиве будет обрезано до нулевого байта.
  • Косая черта в начале имени файла может привести к невозможности открытия архива в некоторых zip-программах в системах Windows.

ZipFile.writestr(zinfo_or_arcname, data, compress_type=None, compresslevel=None):

Метод ZipFile.writestr() записывает файл в архив.

Аргумент data это данные (содержимое) файла, которые могут быть str или bytes. Если данные представляют из себя строки str, то они сначала кодируется как UTF-8.

Аргумент zinfo_or_arcname - это либо имя файла, которое будет дано в архиве, либо объект ZipInfo. Если это объект ZipInfo, то необходимо указать аргумент data. Если это имя файла, то дата и время устанавливаются на текущую дату и время. Архив должен быть открыт в режиме 'w', 'x' или 'a'.

Если задан аргумент compress_type, то он переопределяет значение этого параметра, заданное при создании экземпляра класса zipfile.ZipFile для добавления в архив нового элемента. Аналогично, если задан аргумент compresslevel, то он переопределит конструктор.

import zipfile

text = 'Это новый текстовый файл в архиве.'
filename = 'ReadMe.txt'

# добавляем текстовый файл в архив
with zipfile.ZipFile('test.zip', mode='a', \
                     compression=zipfile.ZIP_DEFLATED) as zf:
    zf.writestr(filename, text)

# прочитаем добавленный текстовый файл в архив
with zipfile.ZipFile('test.zip') as zf:
    byte_text = zf.read(filename)
    print(byte_text.decode('utf-8'))

# Это новый текстовый файл в архиве.

Примечание. При передаче экземпляра zipfile.ZipInfo() в качестве параметра zinfo_or_arcname используется метод сжатия, указанный в элементе compress_type данного экземпляра. По умолчанию конструктор zipfile.ZipInfo() устанавливает для этого члена значение zipfile.ZIP_STORED.

ZipFile.mkdir(zinfo_or_directory, mode=511):

Метод ZipFile.mkdir() создает каталог внутри архива.

Если аргумент zinfo_or_directory является строкой, то внутри архива создается каталог с режимом, указанным в mode. Однако если zinfo_or_directory является экземпляром ZipInfo, то аргумент mode игнорируется.

Архив должен быть открыт в режиме 'w', 'x' или 'a'.

Новое в Python 3.11.

Атрибуты данных

ZipFile.filename:

Атрибут ZipFile.filename возвращает имя файла ZIP.

import zipfile

with zipfile.ZipFile('test.zip') as zf:
    filename = zf.filename
    print(filename)

# test.zip

ZipFile.debug:

Атрибут ZipFile.debug устанавливает уровень вывода отладочной информации. Уровень может быть установлен от 0 (по умолчанию, без выходных данных) до 3-х (максимальный выходной). Отладочная информация записывается в sys.stdout.

ZipFile.comment:

Атрибут ZipFile.comment возвращает комментарий, связанный с файлом ZIP как объект байтов.

При назначении комментария экземпляру класса zipfile.ZipFile, созданному в режиме 'w', 'x' или 'a', он должен быть не длиннее 65535 байт. Комментарии длиннее этого будут усечены.

import zipfile

# добавим комментарий к архиву для этого
# архив открываем в режиме mode='a'
comment = 'Комментарий к архиву'
with zipfile.ZipFile('test.zip', 'a') as zf:
    zf.comment = comment.encode('utf-8')

# теперь читаем комментарий
with zipfile.ZipFile('test.zip') as zf:
    text = zf.comment
    print(text.decode('utf-8'))

# Комментарий к архиву