zipfile no Python: arquivos ZIP seguros

Publicado em: 27/07/2026
Tempo de leitura: 5 minutos
Ícone de arquivo ZIP para artigo sobre zipfile no Python

O módulo zipfile no Python faz parte da biblioteca padrão e permite criar, ler, inspecionar e extrair arquivos ZIP sem instalar dependências externas. Ele é útil em backups, exportações de relatórios, distribuição de documentos, processamento de uploads e automações que precisam reunir vários arquivos em um único pacote.

Apesar de a API ser simples, um fluxo confiável precisa cuidar de nomes internos, tamanho dos arquivos, integridade, duplicatas e caminhos de extração. Neste guia, você aprenderá a trabalhar com ZipFile, escolher modos de abertura, escrever dados da memória, ler conteúdo sem extrair tudo, validar entradas e organizar uma rotina segura. O assunto se conecta a outros recursos da biblioteca padrão, como graphlib para dependências, contextvars para contexto seguro, heapq para filas de prioridade e singledispatch para APIs extensíveis.

Como abrir um arquivo ZIP

A classe principal é zipfile.ZipFile. O modo r abre um pacote para leitura, w cria ou substitui, a acrescenta conteúdo e x cria um novo arquivo, falhando quando o destino já existe.

from zipfile import ZipFile

with ZipFile("dados.zip", "r") as arquivo:
    print(arquivo.namelist())

O gerenciador de contexto fecha o arquivo corretamente. Isso é importante porque o ZIP mantém um diretório central com os metadados dos membros. Se a gravação não for finalizada, o pacote pode ficar incompleto.

Criando um pacote

Use write() para adicionar arquivos do disco. O argumento arcname define o nome interno e evita expor caminhos locais desnecessários.

from zipfile import ZIP_DEFLATED, ZipFile

with ZipFile("backup.zip", "w", compression=ZIP_DEFLATED) as arquivo:
    arquivo.write("relatorios/vendas.csv", arcname="vendas.csv")
    arquivo.write("config/app.json", arcname="config/app.json")

Defina nomes internos curtos e portáveis. Não armazene caminhos absolutos e evite incluir diretórios temporários ou nomes específicos do servidor.

Escrevendo conteúdo da memória

Quando o conteúdo já está em uma string ou sequência de bytes, writestr() dispensa um arquivo temporário.

from zipfile import ZIP_DEFLATED, ZipFile

texto = "id,nome\n1,Ana\n2,Caio\n"
with ZipFile("exportacao.zip", "w", ZIP_DEFLATED) as arquivo:
    arquivo.writestr("clientes.csv", texto)

Essa técnica funciona bem para relatórios pequenos gerados sob demanda. Para dados grandes, considere um arquivo temporário ou processamento em blocos para não manter tudo na memória.

Lendo sem extrair

O método read() devolve bytes de um membro. Já open() retorna um objeto semelhante a arquivo e permite processamento gradual.

from zipfile import ZipFile

with ZipFile("dados.zip") as arquivo:
    with arquivo.open("config.json") as entrada:
        texto = entrada.read().decode("utf-8")
        print(texto)

Essa abordagem é útil quando você quer enviar o conteúdo para um parser de JSON, CSV ou XML sem criar uma cópia no disco.

Inspecionando membros

infolist() retorna objetos ZipInfo com nome, tamanho original, tamanho compactado, data e método de compressão.

with ZipFile("upload.zip") as arquivo:
    for item in arquivo.infolist():
        print(item.filename, item.file_size, item.compress_size)

Inspecione essas informações antes de extrair. É possível limitar extensões, quantidade de membros, tamanho individual e tamanho total.

Validando caminhos

O nome de um membro deve ser tratado como entrada externa. Resolva o caminho final e confirme que ele permanece dentro do diretório autorizado.

from pathlib import Path
from zipfile import ZipFile

raiz = Path("recebidos").resolve()
with ZipFile("upload.zip") as arquivo:
    for item in arquivo.infolist():
        destino = (raiz / item.filename).resolve()
        if raiz not in destino.parents and destino != raiz:
            raise ValueError(f"Nome de arquivo inválido: {item.filename}")
        arquivo.extract(item, raiz)

Também rejeite caminhos absolutos, nomes vazios inesperados e componentes que não sejam necessários ao seu caso de uso.

Aplicando limites de recursos

Um arquivo compactado pequeno pode expandir para uma quantidade muito maior de dados. Defina limites por membro e por pacote.

MAX_ARQUIVO = 50 * 1024 * 1024
MAX_TOTAL = 200 * 1024 * 1024

total = 0
for item in arquivo.infolist():
    if item.file_size > MAX_ARQUIVO:
        raise ValueError("Arquivo interno acima do limite")
    total += item.file_size
    if total > MAX_TOTAL:
        raise ValueError("Pacote acima do limite total")

Durante a cópia, conte os bytes realmente lidos. Assim, a aplicação pode interromper a operação caso os metadados não correspondam ao conteúdo.

Verificando integridade

testzip() lê os membros e verifica o CRC. Ele retorna o primeiro nome com problema ou None quando tudo está consistente.

from zipfile import BadZipFile, ZipFile

try:
    with ZipFile("arquivo.zip") as arquivo:
        problema = arquivo.testzip()
        if problema:
            raise ValueError(f"Membro corrompido: {problema}")
except BadZipFile:
    print("Arquivo ZIP inválido")

Em APIs, registre os detalhes internamente e devolva ao cliente uma mensagem simples, sem expor caminhos do servidor.

Escolhendo a compressão

ZIP_DEFLATED é uma opção amplamente compatível. BZIP2 e LZMA podem reduzir mais alguns tipos de dados, mas nem todos os consumidores antigos oferecem suporte. Imagens JPEG, vídeos e arquivos já compactados costumam apresentar pouco ganho.

O parâmetro compresslevel controla o equilíbrio entre velocidade e tamanho. Meça o resultado com dados reais antes de aumentar o nível em processos frequentes.

Tratando nomes duplicados

Um pacote pode conter mais de uma entrada com o mesmo nome. Isso pode gerar resultados diferentes entre ferramentas. Normalize e registre os nomes antes da extração.

vistos = set()
for item in arquivo.infolist():
    nome = item.filename.replace("\\", "/").casefold()
    if nome in vistos:
        raise ValueError(f"Nome duplicado: {item.filename}")
    vistos.add(nome)

Considere diferenças entre maiúsculas e minúsculas, barras e caracteres Unicode equivalentes.

Extração controlada

Para entradas externas, prefira inspecionar e copiar um membro por vez. Isso permite aplicar regras, acompanhar progresso e remover arquivos parciais em caso de falha.

import shutil

for item in arquivo.infolist():
    destino = raiz / item.filename
    if item.is_dir():
        destino.mkdir(parents=True, exist_ok=True)
        continue
    destino.parent.mkdir(parents=True, exist_ok=True)
    with arquivo.open(item) as origem, destino.open("wb") as saida:
        shutil.copyfileobj(origem, saida, length=1024 * 1024)

Arquivos protegidos por senha

A biblioteca padrão consegue ler alguns ZIPs criptografados tradicionais, mas não é adequada para proteção moderna de dados sensíveis. Para confidencialidade real, use ferramentas e formatos com criptografia atual e gestão correta de chaves.

Testes importantes

Inclua testes para pacote vazio, arquivo inexistente, ZIP corrompido, nomes duplicados, diretórios, caracteres acentuados, arquivos grandes, limite total e caminho inválido. Verifique também se arquivos parciais são removidos após uma exceção.

Boas práticas

  • Use with em todas as operações.
  • Defina nomes internos com arcname.
  • Valide caminhos antes da extração.
  • Limite tamanho individual, total e quantidade de membros.
  • Rejeite nomes duplicados e extensões proibidas.
  • Verifique a integridade quando necessário.
  • Extraia em diretório temporário isolado.
  • Não execute automaticamente arquivos extraídos.
  • Registre falhas e limpe resultados incompletos.
  • Teste com entradas válidas e inválidas.

Conclusão

O zipfile no Python cobre os principais casos de criação e leitura de arquivos ZIP. Para produção, combine a API com validação de nomes, limites de recursos, inspeção de metadados e extração controlada.

Ao tratar cada membro como entrada externa e verificar o destino antes de gravar, sua aplicação fica mais previsível e resistente a pacotes problemáticos. Consulte a documentação oficial de zipfile e as orientações da OWASP sobre extração segura.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Detailed shot of a Jungle Carpet Python (Morelia spilota cheynei) in its natural habitat.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    urllib.parse no Python: manipule URLs

    Aprenda urllib.parse no Python para decompor URLs, criar queries, codificar componentes e evitar riscos com urljoin, redirects e SSRF.

    Ler mais

    Tempo de leitura: 6 minutos
    18/08/2026
    A person typing on a laptop with a Python programming book visible, capturing technology and learning.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ipaddress no Python: redes IPv4 e IPv6

    Aprenda ipaddress no Python para validar IPv4 e IPv6, calcular redes CIDR, dividir sub-redes e criar políticas de acesso seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    18/08/2026
    A vibrant collection of blue sewing threads arranged with hands on a white background.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    queue no Python: coordene threads

    Aprenda queue no Python para coordenar threads com FIFO, prioridade, backpressure, task_done, join, retries e shutdown seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    A male software engineer working on code in a modern office setting.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    struct no Python: trabalhe com binário

    Aprenda struct no Python para empacotar dados binários, controlar endianness, usar buffers e validar protocolos e arquivos externos.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Close-up of a laptop screen with code and a coffee mug, perfect for tech abstract themes.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tarfile no Python: crie TAR seguro

    Aprenda tarfile no Python para criar TAR comprimido, inspecionar membros e extrair com filtros, limites e proteção contra path traversal.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Row of colorful office binders neatly arranged on a shelf, ideal for organization concepts.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    gzip no Python: comprima arquivos .gz

    Aprenda gzip no Python para ler e gravar .gz, criar saídas reproduzíveis, trabalhar com streams e limitar a expansão de

    Ler mais

    Tempo de leitura: 4 minutos
    17/08/2026