Compressão e arquivos ZIP
1. Introdução ao módulo zipfile
O módulo zipfile da biblioteca padrão do Python oferece ferramentas completas para criação, leitura, escrita e extração de arquivos ZIP. Suas classes principais são ZipFile (para manipular o arquivo ZIP em si) e ZipInfo (que armazena metadados de cada membro do arquivo).
Os modos de abertura seguem a mesma lógica de arquivos comuns:
- 'r' — leitura (padrão)
- 'w' — escrita (cria ou sobrescreve)
- 'a' — anexação (adiciona a um ZIP existente)
- 'x' — criação exclusiva (falha se o arquivo já existir)
O uso de context managers (with) é altamente recomendado para garantir o fechamento adequado do arquivo ZIP, mesmo em caso de exceções:
import zipfile
with zipfile.ZipFile('exemplo.zip', 'w') as zf:
zf.write('dados.txt')
# O arquivo é fechado automaticamente ao sair do bloco
2. Criando arquivos ZIP
Para criar um arquivo ZIP, utilizamos o modo 'w'. O método .write() adiciona arquivos individuais ao ZIP:
import zipfile
with zipfile.ZipFile('meu_arquivo.zip', 'w') as zf:
zf.write('documento.txt')
zf.write('imagem.png')
zf.write('pasta/relatorio.pdf') # Preserva estrutura de diretório
Para adicionar diretórios inteiros preservando a estrutura de pastas, podemos percorrer recursivamente:
import os
import zipfile
def adicionar_diretorio(zip_obj, caminho, prefixo=''):
for raiz, _, arquivos in os.walk(caminho):
for arquivo in arquivos:
caminho_completo = os.path.join(raiz, arquivo)
arcname = os.path.relpath(caminho_completo, os.path.dirname(caminho))
zip_obj.write(caminho_completo, arcname)
with zipfile.ZipFile('backup.zip', 'w') as zf:
adicionar_diretorio(zf, 'meus_documentos')
O módulo oferece diferentes métodos de compressão através das constantes:
- ZIP_STORED — sem compressão (apenas armazenamento)
- ZIP_DEFLATED — compressão DEFLATE (padrão, boa relação tamanho/velocidade)
- ZIP_BZIP2 — compressão BZIP2 (melhor taxa, mais lento)
- ZIP_LZMA — compressão LZMA (alta taxa, disponível apenas em Python 3.3+)
import zipfile
with zipfile.ZipFile('compactado.zip', 'w', zipfile.ZIP_DEFLATED) as zf:
zf.write('grande_arquivo.log')
# Nível de compressão (0-9, apenas para DEFLATE)
with zipfile.ZipFile('otimizado.zip', 'w', zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
zf.write('dados_binarios.dat')
3. Extraindo e lendo conteúdo de ZIPs
A extração completa é feita com .extractall(), que recria a estrutura de diretórios no destino:
import zipfile
with zipfile.ZipFile('meu_arquivo.zip', 'r') as zf:
zf.extractall('pasta_destino') # Extrai tudo
zf.extract('documento.txt', 'outra_pasta') # Extrai apenas um arquivo
Para navegar pelos membros do arquivo:
with zipfile.ZipFile('dados.zip', 'r') as zf:
# Lista todos os nomes
for nome in zf.namelist():
print(f'Arquivo: {nome}')
# Informações detalhadas com ZipInfo
info = zf.getinfo('documento.txt')
print(f'Tamanho original: {info.file_size} bytes')
print(f'Tamanho comprimido: {info.compress_size} bytes')
print(f'Data de modificação: {info.date_time}')
Para ler conteúdo diretamente em memória sem extrair para disco:
import zipfile
from io import TextIOWrapper
with zipfile.ZipFile('textos.zip', 'r') as zf:
# Lê como bytes
dados = zf.read('notas.txt')
print(dados.decode('utf-8'))
# Lê como texto (útil para arquivos grandes)
with TextIOWrapper(zf.open('relatorio.csv', 'r'), encoding='utf-8') as arquivo:
for linha in arquivo:
print(linha.strip())
4. Trabalhando com metadados e segurança
A classe ZipInfo expõe diversos atributos úteis:
import zipfile
import datetime
with zipfile.ZipFile('info.zip', 'r') as zf:
info = zf.getinfo('arquivo_importante.pdf')
print(f'Nome: {info.filename}')
print(f'Tamanho original: {info.file_size} bytes')
print(f'Tamanho comprimido: {info.compress_size} bytes')
print(f'Taxa de compressão: {info.compress_size / info.file_size:.2%}')
print(f'CRC32: {hex(info.CRC)}')
# Convertendo data para datetime
data_mod = datetime.datetime(*info.date_time)
print(f'Modificado em: {data_mod}')
O suporte nativo a senhas é limitado — apenas o método de criptografia ZIP 2.0 (fraco) é suportado:
import zipfile
# Criando ZIP com senha
with zipfile.ZipFile('protegido.zip', 'w', zipfile.ZIP_DEFLATED) as zf:
zf.setpassword(b'minha_senha')
zf.write('confidencial.txt')
# Extraindo com senha
with zipfile.ZipFile('protegido.zip', 'r') as zf:
zf.setpassword(b'minha_senha')
zf.extractall('extraido')
Para validação de integridade:
with zipfile.ZipFile('dados.zip', 'r') as zf:
# .testzip() retorna o nome do primeiro arquivo corrompido ou None
resultado = zf.testzip()
if resultado:
print(f'Arquivo corrompido: {resultado}')
else:
print('Integridade OK')
5. Compressão avançada com shutil
O módulo shutil oferece funções de alto nível para compactação:
import shutil
# Criando ZIP a partir de um diretório
shutil.make_archive('backup', 'zip', 'pasta_para_backup')
# Extração simplificada
shutil.unpack_archive('backup.zip', 'destino')
# Formatos suportados: 'zip', 'tar', 'gztar', 'bztar', 'xztar'
print(shutil.get_archive_formats())
# [('bztar', "bzip2'ed tar-file"), ('gztar', "gzip'ed tar-file"),
# ('tar', 'uncompressed tar file'), ('xztar', "xz'ed tar-file"),
# ('zip', 'ZIP file')]
6. Manipulação de grandes volumes e streaming
Para escrita incremental, use o modo 'a' (anexação):
import zipfile
# Criando ZIP em etapas
with zipfile.ZipFile('logs.zip', 'a') as zf:
zf.write('log_dia_1.txt')
# Mais tarde...
with zipfile.ZipFile('logs.zip', 'a') as zf:
zf.write('log_dia_2.txt')
Para manipular arquivos ZIP em memória (sem gravar em disco), use BytesIO:
import zipfile
from io import BytesIO
# Criando ZIP em memória
buffer = BytesIO()
with zipfile.ZipFile(buffer, 'w', zipfile.ZIP_DEFLATED) as zf:
zf.writestr('dados.txt', 'Conteúdo importante')
zf.writestr('notas.csv', 'id,nome,valor\n1,João,100')
# Lendo o ZIP da memória
buffer.seek(0)
with zipfile.ZipFile(buffer, 'r') as zf:
print(zf.read('dados.txt').decode())
# Enviando por HTTP, por exemplo
# response = requests.post(url, files={'arquivo': buffer.getvalue()})
Para processar ZIPs muito grandes sem carregar tudo em memória:
import zipfile
def filtrar_arquivos_grandes(caminho_zip, limite_mb=10):
"""Extrai apenas arquivos menores que o limite."""
with zipfile.ZipFile(caminho_zip, 'r') as zf:
for info in zf.infolist():
if info.file_size < limite_mb * 1024 * 1024:
zf.extract(info.filename)
print(f'Extraído: {info.filename}')
else:
print(f'Ignorado (grande): {info.filename}')
filtrar_arquivos_grandes('backup_completo.zip', limite_mb=50)
7. Interoperabilidade e casos práticos
Integração com pathlib.Path para gerenciamento moderno de caminhos:
from pathlib import Path
import zipfile
pasta = Path('documentos')
with zipfile.ZipFile('documentos.zip', 'w') as zf:
for arquivo in pasta.rglob('*'):
if arquivo.is_file():
# Preserva estrutura relativa
arcname = str(arquivo.relative_to(pasta.parent))
zf.write(arquivo, arcname)
Lendo ZIPs diretamente de respostas HTTP:
import requests
import zipfile
from io import BytesIO
response = requests.get('https://exemplo.com/dados.zip')
response.raise_for_status()
with zipfile.ZipFile(BytesIO(response.content)) as zf:
for nome in zf.namelist():
if nome.endswith('.csv'):
dados = zf.read(nome)
print(f'Processando {nome} com {len(dados)} bytes')
Script simples de backup e compactação de logs:
import zipfile
import os
from datetime import datetime, timedelta
def compactar_logs_antigos(diretorio_logs, dias=7):
"""Compacta logs mais antigos que N dias."""
data_limite = datetime.now() - timedelta(days=dias)
nome_zip = f'logs_antigos_{datetime.now():%Y%m%d}.zip'
with zipfile.ZipFile(nome_zip, 'w', zipfile.ZIP_DEFLATED) as zf:
for arquivo in Path(diretorio_logs).glob('*.log'):
data_mod = datetime.fromtimestamp(arquivo.stat().st_mtime)
if data_mod < data_limite:
zf.write(arquivo, arquivo.name)
arquivo.unlink() # Remove o original
print(f'Compactado: {arquivo.name}')
print(f'Backup criado: {nome_zip}')
compactar_logs_antigos('/var/log/app', dias=30)
Referências
- Documentação oficial do módulo zipfile — Referência completa com todas as classes, métodos e constantes do módulo zipfile.
- Documentação do módulo shutil — Funções de alto nível para compactação e extração de arquivos, incluindo make_archive e unpack_archive.
- Real Python: Working with ZIP Files in Python — Tutorial abrangente com exemplos práticos de criação, extração e manipulação de arquivos ZIP.
- GeeksforGeeks: Working with zip files in Python — Guia detalhado com exemplos de código para operações comuns com arquivos ZIP.
- PEP 427 – The Wheel Binary Package Format — Especificação do formato Wheel, que utiliza ZIP como base para distribuição de pacotes Python.
- Python.org: Using the zipfile module — Guia prático oficial sobre como usar o módulo zipfile em projetos Python.