bz2 no Python: comprima com bzip2

Publicado em: 16/08/2026
Tempo de leitura: 5 minutos
Exquisite python skin handbag with intricate snake emblem and elegant design.

O módulo bz2 no Python permite comprimir e descomprimir dados com o algoritmo bzip2 sem instalar uma biblioteca externa. Ele atende desde tarefas pequenas, como compactar uma sequência de bytes em memória, até fluxos maiores que precisam ser processados em blocos. Também oferece uma interface de arquivo compatível com o protocolo de contexto, facilitando leitura e escrita com with.

Bzip2 costuma produzir arquivos menores que gzip em dados textuais repetitivos, embora normalmente consuma mais CPU. Por isso, a escolha deve considerar tamanho, velocidade, compatibilidade e o ambiente que receberá o arquivo. Este guia mostra as APIs principais, os cuidados com memória e as diferenças entre processamento de uma vez e incremental.

Quando usar bz2

Use bz2 quando o formato .bz2 for exigido por um sistema existente, quando você desejar boa taxa de compressão em logs ou textos, ou quando precisar integrar dados produzidos por ferramentas Unix. Para arquivos que serão abertos frequentemente por usuários comuns, ZIP ou gzip podem ser mais convenientes. Para conhecer uma alternativa amplamente suportada, veja o guia sobre zlib no Python.

Compressão rápida em memória

A função bz2.compress() recebe um objeto de bytes e devolve os bytes comprimidos. O nível varia de 1 a 9: valores maiores favorecem tamanho, mas podem gastar mais tempo.

import bz2

dados = ("linha de relatório\n" * 1000).encode("utf-8")
compactado = bz2.compress(dados, compresslevel=9)
restaurado = bz2.decompress(compactado)

assert restaurado == dados
print(len(dados), len(compactado))

Essa abordagem é simples, porém mantém entrada e saída inteiras na memória. Para arquivos grandes, prefira a interface de arquivo ou os objetos incrementais. O artigo sobre leitura de arquivos gigantes apresenta estratégias complementares para evitar picos de RAM.

Grave um arquivo .bz2

bz2.open() funciona de maneira semelhante a open(). Em modo binário, escreva bytes; em modo texto, informe codificação explicitamente.

import bz2

with bz2.open("relatorio.txt.bz2", "wt", encoding="utf-8") as arquivo:
    arquivo.write("produto,quantidade\n")
    arquivo.write("teclado,12\n")
    arquivo.write("monitor,4\n")

O modo wt cria ou substitui o arquivo. Use xt para falhar quando o destino já existir e evitar sobrescrita acidental. O modo at acrescenta um novo fluxo comprimido ao final; a leitura com BZ2File consegue processar fluxos concatenados.

Leia em modo texto

import bz2

with bz2.open("relatorio.txt.bz2", "rt", encoding="utf-8") as arquivo:
    for numero, linha in enumerate(arquivo, start=1):
        print(numero, linha.rstrip())

A iteração é adequada para textos extensos porque entrega uma linha por vez. Trate UnicodeDecodeError quando a codificação for desconhecida. Não use errors="ignore" automaticamente, pois isso pode apagar caracteres e alterar dados silenciosamente.

BZ2File e objetos de arquivo

A classe BZ2File trabalha em modo binário e aceita tanto um caminho quanto um arquivo já aberto. Isso é útil quando outra camada controla o armazenamento.

from bz2 import BZ2File
from pathlib import Path

caminho = Path("dados.bin.bz2")
with BZ2File(caminho, "wb", compresslevel=7) as destino:
    destino.write(b"cabecalho\x00")
    destino.write(b"conteudo" * 500)

A classe implementa grande parte de io.BufferedIOBase, incluindo leitura, escrita, busca quando possível e readinto(). Ela não é segura para leitores ou escritores simultâneos compartilhando a mesma instância. Proteja o acesso com sincronização ou dê uma instância independente a cada tarefa.

Compressão incremental

Quando os dados chegam em blocos, use BZ2Compressor. Cada chamada pode devolver bytes ou uma sequência vazia, porque o compressor mantém buffers internos. No final, flush() é obrigatório.

import bz2

compressor = bz2.BZ2Compressor(compresslevel=6)
partes = []

for bloco in gerar_blocos():
    saida = compressor.compress(bloco)
    if saida:
        partes.append(saida)

partes.append(compressor.flush())
resultado = b"".join(partes)

Depois de flush(), o objeto não pode ser reutilizado. Crie outro compressor para um novo fluxo.

Descompressão incremental com limite

BZ2Decompressor.decompress() aceita max_length, permitindo limitar a saída produzida por chamada. Esse controle é importante ao lidar com conteúdo externo, pois poucos bytes comprimidos podem se expandir muito.

import bz2

dec = bz2.BZ2Decompressor()
saida = bytearray()
limite_total = 20_000_000

for bloco in receber_blocos():
    pendente = bloco
    while pendente or not dec.needs_input:
        trecho = dec.decompress(pendente, max_length=64 * 1024)
        pendente = b""
        saida.extend(trecho)
        if len(saida) > limite_total:
            raise ValueError("conteúdo descompactado excedeu o limite")
        if dec.eof:
            break

Quando needs_input é falso, o descompressor ainda consegue produzir dados sem nova entrada. unused_data guarda bytes encontrados depois do fim do fluxo. Diferentemente de bz2.decompress() e BZ2File, uma única instância incremental não atravessa automaticamente vários fluxos concatenados.

Valide o fim do fluxo

Não considere a operação concluída apenas porque uma chamada retornou bytes. Verifique eof para distinguir um fluxo completo de um arquivo truncado. Trate OSError, EOFError e erros de entrada conforme a API usada.

Evite arquivos compactados maliciosos

Compressão não autentica o conteúdo. Antes de processar dados externos, limite tamanho comprimido, tamanho expandido, quantidade de arquivos, tempo de CPU e profundidade de etapas. Salve em diretório controlado e nunca use o nome fornecido pelo usuário sem normalização. Se o arquivo tiver estrutura de pacote, as mesmas precauções discutidas no guia de arquivos ZIP com Python continuam relevantes.

Escolha o nível de compressão

O nível 9 é o padrão, mas não é automaticamente a melhor escolha. Meça com dados reais. Em pipelines frequentes, nível 5 ou 6 pode oferecer melhor equilíbrio. Dados já comprimidos, como JPEG, MP4 e muitos PDFs, tendem a encolher pouco e apenas desperdiçam CPU.

Compare com gzip, lzma e zlib

  • gzip: geralmente mais rápido e muito compatível.
  • bz2: boa compressão para texto e arquivos históricos.
  • lzma: pode gerar arquivos ainda menores, com maior custo.
  • zlib: indicado para fluxos e protocolos que usam DEFLATE.

O objetivo do arquivo determina a escolha. Para backups de diretórios, um contêiner como TAR combina vários itens antes da compressão. Para dados estruturados de aplicação, mantenha formato e compressão como responsabilidades separadas.

Teste a ida e a volta

Um teste essencial comprime, descomprime e compara os bytes originais. Inclua arquivo vazio, Unicode, dados aleatórios, conteúdo repetitivo, entradas truncadas, níveis diferentes e vários fluxos concatenados.

import bz2
import pytest

@pytest.mark.parametrize("dados", [b"", b"abc", b"x" * 100_000])
def test_round_trip(dados):
    assert bz2.decompress(bz2.compress(dados)) == dados

Boas práticas

  • Use modo texto com codificação explícita.
  • Use with para fechar arquivos.
  • Prefira processamento incremental para grandes volumes.
  • Chame flush() exatamente uma vez no compressor.
  • Verifique eof em entradas parciais.
  • Imponha limite à saída descompactada.
  • Não compartilhe a mesma instância entre threads.
  • Meça nível e algoritmo com dados reais.

Conclusão

O bz2 no Python oferece uma interface completa para bzip2: funções simples, arquivos em modo texto ou binário e objetos incrementais. A API é direta, mas o uso robusto exige atenção a memória, fim de fluxo, streams concatenados e expansão de conteúdo não confiável.

Consulte a documentação oficial do bz2 e o projeto bzip2. Para organizar opções de aplicações que manipulam esses arquivos, veja também configparser no Python.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Detailed view of programming code in a dark theme on a computer screen.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    zlib no Python: comprima dados

    Aprenda zlib no Python para comprimir e descomprimir bytes, processar streams, usar checksums e limitar dados externos.

    Ler mais

    Tempo de leitura: 6 minutos
    16/08/2026
    Diagrama de arquivos e sistema representando configurações INI com configparser no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    configparser no Python: arquivos INI

    Aprenda configparser no Python para ler e gravar arquivos INI, usar defaults, interpolação, tipos e escrita atômica.

    Ler mais

    Tempo de leitura: 6 minutos
    16/08/2026
    Módulo de memória RAM representando gerenciamento de objetos com gc no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    gc no Python: controle o coletor

    Aprenda gc no Python para controlar coleta cíclica, analisar objetos rastreados, diagnosticar vazamentos e observar pausas.

    Ler mais

    Tempo de leitura: 7 minutos
    16/08/2026
    Linhas de código representando rastreamento de execução com trace no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    trace no Python: rastreie execução

    Aprenda trace no Python para contar linhas, rastrear execução, listar funções, acumular cobertura e filtrar módulos.

    Ler mais

    Tempo de leitura: 6 minutos
    16/08/2026
    Notebook com gráficos de desempenho representando análise de perfis com pstats no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pstats no Python: analise perfis

    Aprenda pstats no Python para ordenar, filtrar, combinar e interpretar perfis do cProfile, callers, callees e tempos cumulativos.

    Ler mais

    Tempo de leitura: 6 minutos
    15/08/2026
    Notebook com código representando exemplos executáveis testados com doctest no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    doctest no Python: teste exemplos

    Aprenda doctest no Python para executar exemplos em docstrings e arquivos, normalizar saídas e integrar documentação ao CI.

    Ler mais

    Tempo de leitura: 6 minutos
    15/08/2026