El módulo bz2 en Python comprime y descomprime datos con el algoritmo bzip2 sin instalar paquetes externos. Sirve para operaciones pequeñas en memoria, archivos comprimidos, texto con codificación y streams incrementales procesados por bloques.
Bzip2 suele producir archivos menores que gzip en textos repetitivos, aunque normalmente consume más CPU. La elección correcta depende del tamaño, la velocidad, la compatibilidad y la frecuencia de acceso. Esta guía explica las APIs principales y los controles necesarios cuando los datos comprimidos provienen de fuentes externas.
Cuándo usar bz2
Usa bz2 cuando un flujo existente requiera archivos .bz2, cuando la tasa de compresión sea más importante que la velocidad máxima o cuando intercambies logs y datasets con herramientas Unix. Para una interfaz DEFLATE de nivel inferior, consulta zlib en Python.
Compresión directa en memoria
bz2.compress() recibe bytes y devuelve bytes comprimidos. Los niveles van de 1 a 9. Un valor alto favorece el tamaño, pero puede tardar más.
import bz2
datos = ("fila del informe\n" * 1000).encode("utf-8")
comprimido = bz2.compress(datos, compresslevel=9)
restaurado = bz2.decompress(comprimido)
assert restaurado == datos
print(len(datos), len(comprimido))La solución es sencilla, pero mantiene entrada y salida completas en memoria. Para volúmenes grandes, utiliza archivos o clases incrementales. La guía para leer archivos gigantes con Python presenta técnicas complementarias para controlar la RAM.
Escribe un archivo .bz2
bz2.open() se parece a open(). Los modos binarios reciben bytes y los modos de texto requieren una codificación explícita.
import bz2
with bz2.open("informe.csv.bz2", "wt", encoding="utf-8") as archivo:
archivo.write("producto,cantidad\n")
archivo.write("teclado,12\n")
archivo.write("monitor,4\n")wt reemplaza el destino. Usa xt para fallar si el archivo ya existe. El modo append agrega otro stream comprimido al final; BZ2File puede leer streams concatenados.
Lee línea por línea
import bz2
with bz2.open("informe.csv.bz2", "rt", encoding="utf-8") as archivo:
for numero, linea in enumerate(archivo, start=1):
print(numero, linea.rstrip())La iteración evita cargar todo el texto. Captura UnicodeDecodeError cuando la codificación sea incierta. Evita errors="ignore" como solución automática porque puede eliminar caracteres y corromper datos silenciosamente.
Trabaja con BZ2File
BZ2File funciona en modo binario y acepta una ruta o un objeto de archivo existente. Implementa gran parte de io.BufferedIOBase.
from bz2 import BZ2File
from pathlib import Path
ruta = Path("datos.bin.bz2")
with BZ2File(ruta, "wb", compresslevel=7) as destino:
destino.write(b"cabecera\x00")
destino.write(b"contenido" * 500)La clase admite context manager, iteración, búsqueda cuando está disponible, read1() y readinto(). Una misma instancia no es segura para lecturas o escrituras simultáneas. Entrega un objeto independiente a cada tarea o protege el acceso.
Compresión incremental
BZ2Compressor es apropiado cuando los datos llegan por bloques. compress() puede devolver bytes o una salida vacía porque mantiene buffers internos. Finaliza con flush().
import bz2
compresor = bz2.BZ2Compressor(compresslevel=6)
partes = []
for bloque in generar_bloques():
salida = compresor.compress(bloque)
if salida:
partes.append(salida)
partes.append(compresor.flush())
resultado = b"".join(partes)Después de flush(), el objeto no puede reutilizarse. Crea uno nuevo para cada stream independiente.
Descompresión incremental limitada
BZ2Decompressor.decompress() acepta max_length. Esto limita la salida por llamada y ayuda a proteger servicios contra expansiones inesperadas.
import bz2
dec = bz2.BZ2Decompressor()
salida = bytearray()
limite = 20_000_000
for bloque in recibir_bloques():
pendiente = bloque
while pendiente or not dec.needs_input:
parte = dec.decompress(pendiente, max_length=64 * 1024)
pendiente = b""
salida.extend(parte)
if len(salida) > limite:
raise ValueError("el contenido excedió el límite")
if dec.eof:
breakSi needs_input es falso, todavía existe salida disponible sin nueva entrada. unused_data guarda bytes posteriores al final. A diferencia de bz2.decompress() y BZ2File, una instancia incremental no continúa automáticamente por varios streams concatenados.
Verifica el final
No consideres válido un archivo solo porque produjo algunos bytes. Comprueba eof para distinguir un stream completo de uno truncado. Maneja OSError, EOFError y los errores de validación de tu aplicación.
Protege el sistema de datos hostiles
La compresión no autentica el contenido. Limita el tamaño comprimido, el tamaño expandido, el tiempo de CPU y la cantidad de etapas. Guarda archivos en un directorio controlado, normaliza nombres y no confíes en la extensión. Para contenedores con rutas, aplica las prácticas de seguridad del artículo sobre archivos ZIP con Python.
Elige el nivel adecuado
El nivel 9 es el predeterminado, no una respuesta universal. Mide con datos reales. Los niveles 5 o 6 pueden ofrecer un mejor equilibrio en pipelines frecuentes. JPEG, MP4 y muchos PDF ya están comprimidos, por lo que bzip2 suele ahorrar poco.
Compara algoritmos
- gzip: normalmente más rápido y compatible.
- bz2: eficaz para texto y datos históricos.
- lzma: puede reducir más el tamaño con mayor coste.
- zlib: útil para protocolos y streams DEFLATE.
Para backups de directorios, TAR agrupa elementos antes de comprimir. Mantén serialización, archivado y compresión como decisiones separadas.
Prueba ida y vuelta
Un test esencial comprime, descomprime y compara los bytes exactos. Incluye datos vacíos, Unicode codificado, contenido aleatorio, contenido repetitivo, streams truncados, niveles distintos y miembros concatenados.
import bz2
import pytest
@pytest.mark.parametrize("datos", [b"", b"abc", b"x" * 100_000])
def test_round_trip(datos):
assert bz2.decompress(bz2.compress(datos)) == datosBuenas prácticas
- Especifica la codificación en modo texto.
- Usa
withpara cerrar archivos. - Procesa por bloques cuando el volumen sea grande.
- Llama a
flush()una sola vez. - Comprueba
eofen entradas parciales. - Limita la salida descomprimida.
- No compartas una instancia entre hilos.
- Mide con cargas reales.
Conclusión
bz2 en Python proporciona funciones directas, archivos comprimidos, texto e interfaces incrementales para bzip2. La API es clara, pero un sistema robusto debe controlar memoria, límites de stream, miembros concatenados y expansión de contenido no confiable.
Consulta la documentación oficial de bz2 y el proyecto bzip2. Para configuraciones de tareas de compresión, revisa configparser en Python, y para rastrear la ejecución consulta trace en Python.







