Работа с ZIP архивами на Python (модуль zipfile)
Основы работы с zipfile в Python
Модуль zipfile предоставляет инструменты для создания, чтения, записи и извлечения ZIP архивов. Он поддерживает стандартные методы сжатия (ZIP_STORED, ZIP_DEFLATED) и работу с паролями (традиционное шифрование ZIP 2.0). Архивы могут быть файлами на диске или объектами, подобными файлам (BytesIO).
Базовое создание и извлечение архива
Наиболее распространённый подход - использование класса ZipFile в менеджере контекста. Это гарантирует закрытие архива даже при ошибках.
import zipfile
# Создание архива и добавление файла
with zipfile.ZipFile('example.zip', 'w', zipfile.ZIP_DEFLATED) as zf:
zf.write('file1.txt') # добавляем существующий файл
# Извлечение всех файлов
with zipfile.ZipFile('example.zip', 'r') as zf:
zf.extractall('output')
ввод программ на python (ввод данных в программе python)
В режиме 'w' архив создаётся заново; для добавления используйте 'a'. Параметр ZIP_DEFLATED включает сжатие.
Как прочитать содержимое архива без извлечения?
Используйте метод namelist() для получения списка имён файлов и read() для чтения содержимого конкретного файла.
with zipfile.ZipFile('example.zip', 'r') as zf:
print(zf.namelist())
data = zf.read('file1.txt')
print(data.decode('utf-8'))
Python file io (ввод-вывод файлов в python)
Это позволяет работать с файлами в памяти, не записывая их на диск.
Как добавить файл в существующий архив?
Откройте архив в режиме добавления ('a') и используйте write().
with zipfile.ZipFile('example.zip', 'a') as zf:
zf.write('new_file.txt')
Python temp files (временные файлы в python)
Обратите внимание: режим 'a' не перезаписывает архив, а добавляет новые файлы. Если файл с таким именем уже существует, он будет перезаписан.
Как защитить архив паролем?
Укажите пароль при открытии архива для записи или извлечения. Поддерживается только традиционное шифрование ZIP 2.0.
with zipfile.ZipFile('secret.zip', 'w', zipfile.ZIP_DEFLATED) as zf:
zf.setpassword(b'mypassword')
zf.write('secret.txt')
# Извлечение с паролем
with zipfile.ZipFile('secret.zip', 'r') as zf:
zf.setpassword(b'mypassword')
zf.extractall('output_secret')
Python index files (индексация файлов в python)
Важно: пароль должен быть байтовой строкой. setpassword() применяется ко всем последующим операциям с архивом.
Как создать архив из данных в памяти (BytesIO)?
Передайте объект BytesIO в конструктор ZipFile.
import zipfile
from io import BytesIO
buffer = BytesIO()
with zipfile.ZipFile(buffer, 'w', zipfile.ZIP_DEFLATED) as zf:
zf.writestr('data.txt', 'Hello, ZIP!')
# Теперь buffer содержит архив. Можно сохранить или передать.
with open('in_memory.zip', 'wb') as f:
f.write(buffer.getvalue())
File python class (класс для работы с файлами в python)
Метод writestr() позволяет добавить файл из строки или байтов, не создавая физический файл на диске.
Как извлечь только определённые файлы из архива?
Используйте extract() для одного файла или extractall() с параметром members.
with zipfile.ZipFile('example.zip', 'r') as zf:
zf.extract('file1.txt', path='output_single')
# или:
zf.extractall(path='output_selected', members=['file1.txt', 'file2.txt'])
Параметр members принимает список имён файлов для извлечения.
Типичные ошибки и их решение
- BadZipFile: файл не является ZIP архивом или повреждён. Проверьте целостность файла.
- FileNotFoundError: при попытке добавить несуществующий файл через write(). Убедитесь, что файл существует.
- RuntimeError: Password required for extraction: архив зашифрован, но пароль не задан. Установите пароль через setpassword().
- LargeZipFile: возникает, если размер архива превышает 4 ГБ (ZIP32). Используйте ZIP64 (параметр allowZip64=True).
- NotImplementedError: That compression method is not supported: попытка извлечь файл, сжатый методом, не поддерживаемым zipfile. Используйте сторонние библиотеки (например, pyzipper для AES).
Расширенные примеры работы с zipfile
Создание архива с метаданными через ZipInfo
Класс ZipInfo позволяет задать дату, комментарий и атрибуты файла. Пример:
import zipfile
with zipfile.ZipFile('meta_example.zip', 'w', zipfile.ZIP_DEFLATED) as zf:
info = zipfile.ZipInfo('subdir/data.txt')
info.date_time = (2025, 3, 28, 10, 30, 0)
info.comment = b'Important data'
zf.writestr(info, 'This is the content')
Проверка метаданных:
with zipfile.ZipFile('meta_example.zip', 'r') as zf:
for info in zf.infolist():
print(info.filename, info.date_time, info.comment)
# Вывод: subdir/data.txt (2025, 3, 28, 10, 30, 0) b'Important data'
Извлечение с сохранением прав доступа (Unix)
Можно задать права в поле external_attr (сдвинутые на 16 бит). Работает на Unix-подобных системах.
import zipfile
import stat
with zipfile.ZipFile('perm_example.zip', 'w', zipfile.ZIP_DEFLATED) as zf:
info = zipfile.ZipInfo('script.sh')
info.external_attr = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) << 16
content = '''#!/bin/bash
echo 'Hello' '''
zf.writestr(info, content)
with zipfile.ZipFile('perm_example.zip', 'r') as zf:
zf.extract('script.sh')
import os
st = os.stat('script.sh')
print(oct(st.st_mode & 0o777)) # 0o755
Создание архива в памяти для HTTP-ответа
Функция, возвращающая BytesIO с архивом:
from io import BytesIO
import zipfile
def create_zip_in_memory(files_dict):
buffer = BytesIO()
with zipfile.ZipFile(buffer, 'w', zipfile.ZIP_DEFLATED) as zf:
for name, content in files_dict.items():
zf.writestr(name, content)
buffer.seek(0)
return buffer
# Пример использования:
zip_buffer = create_zip_in_memory({'file1.txt': 'Text1', 'file2.txt': 'Text2'})
# Теперь zip_buffer можно передать в HTTP-ответ.
Добавление больших файлов без загрузки в память
Используйте shutil.copyfileobj вместе с потоком внутри архива:
import zipfile
import shutil
import os
def add_large_file(zip_path, file_path, arcname=None):
with zipfile.ZipFile(zip_path, 'a', zipfile.ZIP_DEFLATED) as zf:
with open(file_path, 'rb') as src:
info = zipfile.ZipInfo(arcname or os.path.basename(file_path))
info.date_time = (2025, 3, 28, 12, 0, 0)
with zf.open(info, 'w') as dst:
shutil.copyfileobj(src, dst)
# add_large_file('large_archive.zip', 'bigfile.bin', 'sub/bigfile.bin')
Чтение архива напрямую из URL
Загрузите содержимое URL в BytesIO и откройте как архив:
import zipfile
import requests
from io import BytesIO
response = requests.get('https://example.com/archive.zip')
response.raise_for_status()
buffer = BytesIO(response.content)
with zipfile.ZipFile(buffer, 'r') as zf:
zf.extractall('downloaded_archive')
Этот метод удобен для автоматизации скачивания и распаковки.