Автор оригинала: Doug Hellmann.
Цель:
Чтение и запись файлов ZIP-архивов.
Модуль zipfile
можно использовать для управления файлами ZIP-архивов, форматом, популяризированным программой PKZIP для ПК.
Тестирование файлов ZIP
Функция is_zipfile ()
возвращает логическое значение, указывающее, относится ли имя файла, переданное в качестве аргумента, к допустимому ZIP-архиву.
zipfile_is_zipfile.py
import zipfile for filename in ['README.txt', 'example.zip', 'bad_example.zip', 'notthere.zip']: print('{:>15} {}'.format( filename, zipfile.is_zipfile(filename)))
Если файл вообще не существует, is_zipfile ()
возвращает False
.
$ python3 zipfile_is_zipfile.py README.txt False example.zip True bad_example.zip False notthere.zip False
Чтение метаданных из архива
Используйте класс ZipFile
для работы непосредственно с ZIP-архивом. Он поддерживает методы для чтения данных о существующих архивах, а также для изменения архивов путем добавления дополнительных файлов.
zipfile_namelist.py
import zipfile with zipfile.ZipFile('example.zip', 'r') as zf: print(zf.namelist())
Метод namelist ()
возвращает имена файлов в существующем архиве.
$ python3 zipfile_namelist.py ['README.txt']
Однако список имен – это лишь часть информации, доступной из архива. Чтобы получить доступ ко всем метаданным о содержимом ZIP, используйте методы infolist ()
или getinfo ()
.
zipfile_infolist.py
import datetime import zipfile def print_info(archive_name): with zipfile.ZipFile(archive_name) as zf: for info in zf.infolist(): print(info.filename) print(' Comment :', info.comment) mod_date datetime.datetime(*info.date_time) print(' Modified :', mod_date) if info.create_system 0: system 'Windows' elif info.create_system 3: system 'Unix' else: system 'UNKNOWN' print(' System :', system) print(' ZIP version :', info.create_version) print(' Compressed :', info.compress_size, 'bytes') print(' Uncompressed:', info.file_size, 'bytes') print() if __name__ '__main__': print_info('example.zip')
Есть и дополнительные поля, помимо напечатанных здесь, но расшифровка значений во что-нибудь полезное требует внимательного чтения Замечания по применению PKZIP со спецификацией файла ZIP.
$ python3 zipfile_infolist.py README.txt Comment : b'' Modified : 2010-11-15 06:48:02 System : Unix ZIP version : 30 Compressed : 65 bytes Uncompressed: 76 bytes
Если имя элемента архива известно заранее, его объект ZipInfo
можно получить напрямую с помощью getinfo ()
.
zipfile_getinfo.py
import zipfile with zipfile.ZipFile('example.zip') as zf: for filename in ['README.txt', 'notthere.txt']: try: info zf.getinfo(filename) except KeyError: print('ERROR: Did not find {} in zip file'.format( filename)) else: print('{} is {} bytes'.format( info.filename, info.file_size))
Если элемент архива отсутствует, getinfo ()
вызывает KeyError
.
$ python3 zipfile_getinfo.py README.txt is 76 bytes ERROR: Did not find notthere.txt in zip file
Извлечение заархивированных файлов из архива
Чтобы получить доступ к данным из члена архива, используйте метод read ()
, передав имя члена.
zipfile_read.py
import zipfile with zipfile.ZipFile('example.zip') as zf: for filename in ['README.txt', 'notthere.txt']: try: data zf.read(filename) except KeyError: print('ERROR: Did not find {} in zip file'.format( filename)) else: print(filename, ':') print(data) print()
При необходимости данные автоматически распаковываются.
$ python3 zipfile_read.py README.txt : b'The examples for the zipfile module use \nthis file and exampl e.zip as data.\n' ERROR: Did not find notthere.txt in zip file
Создание новых архивов
Чтобы создать новый архив, создайте экземпляр ZipFile
с режимом 'w'
. Любой существующий файл обрезается и запускается новый архив. Для добавления файлов используйте метод write ()
.
zipfile_write.py
from zipfile_infolist import print_info import zipfile print('creating archive') with zipfile.ZipFile('write.zip', mode'w') as zf: print('adding README.txt') zf.write('README.txt') print() print_info('write.zip')
По умолчанию содержимое архива не сжимается.
$ python3 zipfile_write.py creating archive adding README.txt README.txt Comment : b'' Modified : 2016-08-07 13:31:24 System : Unix ZIP version : 20 Compressed : 76 bytes Uncompressed: 76 bytes
Для добавления сжатия требуется модуль zlib. Если доступен zlib, режим сжатия для отдельных файлов или для архива в целом можно установить с помощью zipfile.ZIP_DEFLATED
. Режим сжатия по умолчанию – zipfile.ZIP_STORED
, который добавляет входные данные в архив без сжатия.
zipfile_write_compression.py
from zipfile_infolist import print_info import zipfile try: import zlib compression zipfile.ZIP_DEFLATED except (ImportError, AttributeError): compression zipfile.ZIP_STORED modes { zipfile.ZIP_DEFLATED: 'deflated', zipfile.ZIP_STORED: 'stored', } print('creating archive') with zipfile.ZipFile('write_compression.zip', mode'w') as zf: mode_name modes[compression] print('adding README.txt with compression mode', mode_name) zf.write('README.txt', compress_typecompression) print() print_info('write_compression.zip')
На этот раз элемент архива сжат.
$ python3 zipfile_write_compression.py creating archive adding README.txt with compression mode deflated README.txt Comment : b'' Modified : 2016-08-07 13:31:24 System : Unix ZIP version : 20 Compressed : 65 bytes Uncompressed: 76 bytes
Использование альтернативных имен членов архива
Передайте значение arcname
в write ()
, чтобы добавить файл в архив с именем, отличным от исходного имени файла.
zipfile_write_arcname.py
from zipfile_infolist import print_info import zipfile with zipfile.ZipFile('write_arcname.zip', mode'w') as zf: zf.write('README.txt', arcname'NOT_README.txt') print_info('write_arcname.zip')
В архиве нет никаких признаков оригинального имени файла.
$ python3 zipfile_write_arcname.py NOT_README.txt Comment : b'' Modified : 2016-08-07 13:31:24 System : Unix ZIP version : 20 Compressed : 76 bytes Uncompressed: 76 bytes
Запись данных из источников, отличных от файлов
Иногда необходимо записать в ZIP-архив данные, полученные не из существующего файла. Вместо того, чтобы записывать данные в файл, а затем добавлять этот файл в ZIP-архив, используйте метод writerestr ()
, чтобы напрямую добавить строку байтов в архив.
zipfile_writestr.py
from zipfile_infolist import print_info import zipfile msg 'This data did not exist in a file.' with zipfile.ZipFile('writestr.zip', mode'w', compressionzipfile.ZIP_DEFLATED, ) as zf: zf.writestr('from_string.txt', msg) print_info('writestr.zip') with zipfile.ZipFile('writestr.zip', 'r') as zf: print(zf.read('from_string.txt'))
В этом случае аргумент compress_type
для ZipFile
использовался для сжатия данных, поскольку writestr ()
не принимает аргумент для указания сжатия .
$ python3 zipfile_writestr.py from_string.txt Comment : b'' Modified : 2016-12-29 12:14:42 System : Unix ZIP version : 20 Compressed : 36 bytes Uncompressed: 34 bytes b'This data did not exist in a file.'
Запись с помощью экземпляра ZipInfo
Обычно дата модификации вычисляется при добавлении файла или строки в архив. Экземпляр ZipInfo
можно передать в Writestr ()
для определения даты изменения и других метаданных.
zipfile_writestr_zipinfo.py
import time import zipfile from zipfile_infolist import print_info msg b'This data did not exist in a file.' with zipfile.ZipFile('writestr_zipinfo.zip', mode'w', ) as zf: info zipfile.ZipInfo('from_string.txt', date_timetime.localtime(time.time()), ) info.compress_type zipfile.ZIP_DEFLATED info.comment b'Remarks go here' info.create_system 0 zf.writestr(info, msg) print_info('writestr_zipinfo.zip')
В этом примере измененное время устанавливается на текущее время, данные сжимаются, и используется значение false для create_system
. С новым файлом также связан простой комментарий.
$ python3 zipfile_writestr_zipinfo.py from_string.txt Comment : b'Remarks go here' Modified : 2016-12-29 12:14:42 System : Windows ZIP version : 20 Compressed : 36 bytes Uncompressed: 34 bytes
Добавление к файлам
Помимо создания новых архивов, можно добавить к существующему архиву или добавить архив в конец существующего файла (например, файл .exe
для самораспаковывающегося архива). Чтобы открыть файл для добавления к нему, используйте режим 'a'
.
zipfile_append.py
from zipfile_infolist import print_info import zipfile print('creating archive') with zipfile.ZipFile('append.zip', mode'w') as zf: zf.write('README.txt') print() print_info('append.zip') print('appending to the archive') with zipfile.ZipFile('append.zip', mode'a') as zf: zf.write('README.txt', arcname'README2.txt') print() print_info('append.zip')
Результирующий архив содержит два члена:
$ python3 zipfile_append.py creating archive README.txt Comment : b'' Modified : 2016-08-07 13:31:24 System : Unix ZIP version : 20 Compressed : 76 bytes Uncompressed: 76 bytes appending to the archive README.txt Comment : b'' Modified : 2016-08-07 13:31:24 System : Unix ZIP version : 20 Compressed : 76 bytes Uncompressed: 76 bytes README2.txt Comment : b'' Modified : 2016-08-07 13:31:24 System : Unix ZIP version : 20 Compressed : 76 bytes Uncompressed: 76 bytes
ZIP-архивы Python
Python может импортировать модули из ZIP-архивов с помощью zipimport, если эти архивы находятся в sys.path
. Класс PyZipFile
можно использовать для создания модуля, подходящего для использования таким образом. Дополнительный метод writepy ()
указывает PyZipFile
сканировать каталог на наличие файлов .py
и добавлять соответствующие .pyo
или файл .pyc
в архив. Если ни одна скомпилированная форма не существует, создается и добавляется файл .pyc
.
zipfile_pyzipfile.py
import sys import zipfile if __name__ '__main__': with zipfile.PyZipFile('pyzipfile.zip', mode'w') as zf: zf.debug 3 print('Adding python files') zf.writepy('.') for name in zf.namelist(): print(name) print() sys.path.insert(0, 'pyzipfile.zip') import zipfile_pyzipfile print('Imported from:', zipfile_pyzipfile.__file__)
Если для атрибута отладки PyZipFile
задано значение 3
, включена подробная отладка и вывод производится по мере компиляции каждого найденного файла .py
.
$ python3 zipfile_pyzipfile.py Adding python files Adding files from directory . Compiling ./zipfile_append.py Adding zipfile_append.pyc Compiling ./zipfile_getinfo.py Adding zipfile_getinfo.pyc Compiling ./zipfile_infolist.py Adding zipfile_infolist.pyc Compiling ./zipfile_is_zipfile.py Adding zipfile_is_zipfile.pyc Compiling ./zipfile_namelist.py Adding zipfile_namelist.pyc Compiling ./zipfile_printdir.py Adding zipfile_printdir.pyc Compiling ./zipfile_pyzipfile.py Adding zipfile_pyzipfile.pyc Compiling ./zipfile_read.py Adding zipfile_read.pyc Compiling ./zipfile_write.py Adding zipfile_write.pyc Compiling ./zipfile_write_arcname.py Adding zipfile_write_arcname.pyc Compiling ./zipfile_write_compression.py Adding zipfile_write_compression.pyc Compiling ./zipfile_writestr.py Adding zipfile_writestr.pyc Compiling ./zipfile_writestr_zipinfo.py Adding zipfile_writestr_zipinfo.pyc zipfile_append.pyc zipfile_getinfo.pyc zipfile_infolist.pyc zipfile_is_zipfile.pyc zipfile_namelist.pyc zipfile_printdir.pyc zipfile_pyzipfile.pyc zipfile_read.pyc zipfile_write.pyc zipfile_write_arcname.pyc zipfile_write_compression.pyc zipfile_writestr.pyc zipfile_writestr_zipinfo.pyc Imported from: pyzipfile.zip/zipfile_pyzipfile.pyc
Ограничения
Модуль zipfile
не поддерживает файлы ZIP с добавленными комментариями или многодисковые архивы. Он поддерживает файлы ZIP размером более 4 ГБ, в которых используются расширения ZIP64.
Смотрите также
- стандартная библиотека документации для zipfile
- zlib – библиотека сжатия ZIP
- tarfile – чтение и запись архивов tar
- zipimport – Импорт модулей Python из архива ZIP.
- Примечания к приложению PKZIP – официальная спецификация формата архива ZIP.