sqlite3.Blob: lee BLOBs sin cargar todo en memoria

Publicado el: 12/09/2026
Tempo de leitura: 5 minutos
Portátil con código digital que representa datos BLOB en SQLite

sqlite3.Blob en Python permite leer y escribir partes de un campo BLOB de SQLite sin cargar todo el contenido en memoria. Es útil cuando una base de datos almacena imágenes, documentos, archivos comprimidos, modelos u otros datos binarios grandes. En lugar de ejecutar un SELECT que devuelve todos los bytes, la aplicación abre un manejador parecido a un archivo y procesa solo la región necesaria.

Qué representa sqlite3.Blob

Un objeto Blob es un acceso incremental a una columna BLOB existente. Se obtiene con Connection.blobopen. La interfaz ofrece read, write, seek, consulta de longitud, índices y slices. Los datos permanecen dentro de la fila de SQLite, mientras Python trabaja con bloques manejables. Esto reduce picos de memoria y facilita actualizaciones localizadas.

El manejador no cambia el tamaño del valor almacenado. Para reservar espacio, se inserta zeroblob con la cantidad de bytes deseada y luego se abre la columna para escritura. Escribir más allá del límite genera un error. Si el contenido debe crecer o reducirse, hay que crear un nuevo BLOB con el tamaño correcto y reemplazar la columna.

Crear la tabla y reservar espacio

import sqlite3

con = sqlite3.connect("archivos.db")
con.execute("CREATE TABLE IF NOT EXISTS adjuntos (id INTEGER PRIMARY KEY, nombre TEXT, datos BLOB)")
tamano = 1024 * 1024
cur = con.execute("INSERT INTO adjuntos(nombre, datos) VALUES (?, zeroblob(?))", ("ejemplo.bin", tamano))
rowid = cur.lastrowid
con.commit()

zeroblob pide a SQLite que cree un valor binario lleno de ceros sin obligar a Python a construir primero un objeto bytes enorme. La fila obtiene un rowid estable que blobopen puede utilizar. Los nombres de tabla y columna deben coincidir con el esquema y no deberían proceder directamente de una entrada no confiable.

Abrir y escribir el BLOB

with con.blobopen("adjuntos", "datos", rowid, readonly=False) as blob:
    blob.write(b"cabecera-binaria")
    blob.seek(4096)
    blob.write(b"contenido-en-otra-posicion")

El context manager cierra el recurso incluso si ocurre una excepción. La primera escritura comienza en la posición cero. seek mueve el cursor, igual que en un archivo binario. Para transferencias grandes conviene usar bloques constantes, por ejemplo 64 KiB o 1 MiB, y registrar cuántos bytes se han escrito correctamente.

Lectura incremental

with con.blobopen("adjuntos", "datos", rowid, readonly=True) as blob:
    total = len(blob)
    while True:
        parte = blob.read(64 * 1024)
        if not parte:
            break
        procesar(parte)

La lectura incremental es la ventaja principal. La aplicación puede calcular hashes, transmitir una respuesta, validar cabeceras o copiar el contenido a otro destino manteniendo estable el uso de memoria. En aplicaciones web esto reduce el consumo por petición, aunque las transacciones largas y los bloqueos siguen requiriendo cuidado.

Índices y slices

sqlite3.Blob permite acceder por índice. Un índice devuelve un entero entre 0 y 255, mientras un slice devuelve bytes. También se puede reemplazar un byte o una porción del mismo tamaño. Es práctico para cabeceras, flags y formatos binarios con posiciones fijas.

with con.blobopen("adjuntos", "datos", rowid) as blob:
    primero = blob[0]
    cabecera = blob[0:16]
    blob[0] = 0x50
    blob[1:4] = b"YTH"

La asignación de una porción debe caber exactamente en el espacio seleccionado. El objeto no es una lista redimensionable: sobrescribe bytes existentes, no inserta contenido desplazando el resto.

Transacciones y concurrencia

SQLite utiliza transacciones y bloqueos de archivo. Un Blob abierto para escritura participa en ese contexto y puede retrasar commits u operaciones competidoras. Mantén el manejador abierto solo el tiempo necesario. Usa transacciones cortas, configura un timeout razonable y trata OperationalError. No compartas una conexión entre hilos sin una estrategia clara.

Si varios workers pueden modificar el mismo BLOB, define propiedad, bloqueo o una cola de escritura única. SQLite funciona muy bien en aplicaciones locales y cargas moderadas, pero no es un almacén de objetos distribuido. Para archivos enormes, muchos lectores concurrentes o entrega directa por CDN, puede ser mejor usar almacenamiento externo.

Validación e integridad

Valida rowid, nombre lógico, longitud esperada y permisos antes de abrir el BLOB. Después de escribir, calcula un hash criptográfico y compáralo con el valor previsto. Guarda tamaño, tipo MIME y checksum en columnas separadas para detectar truncamientos o contenido incorrecto.

import hashlib

h = hashlib.sha256()
with con.blobopen("adjuntos", "datos", rowid, readonly=True) as blob:
    while parte := blob.read(65536):
        h.update(parte)
print(h.hexdigest())

Para ampliar el contexto, consulta las guías de Academify sobre SQLite con Python, manejo de archivos, pathlib en Python y excepciones en Python. También son referencias esenciales la documentación oficial de sqlite3 y la API incremental de BLOB de SQLite.

Copiar un archivo a SQLite

from pathlib import Path

origen = Path("archivo.bin")
tamano = origen.stat().st_size
cur = con.execute("INSERT INTO adjuntos(nombre, datos) VALUES (?, zeroblob(?))", (origen.name, tamano))
rowid = cur.lastrowid
with origen.open("rb") as src, con.blobopen("adjuntos", "datos", rowid) as dst:
    while bloque := src.read(1024 * 1024):
        dst.write(bloque)
con.commit()

Este patrón mantiene estable la memoria porque solo conserva un bloque cada vez. Si falla la operación, ejecuta rollback y elimina la fila incompleta. Para un proceso reanudable, registra el desplazamiento confirmado y verifica cada bloque antes de continuar.

Cuándo usarlo

Usa sqlite3.Blob cuando el contenido binario pertenezca naturalmente a la misma transacción que otros datos, la aplicación sea local o tenga concurrencia moderada, el tamaño sea conocido y el acceso parcial aporte valor. Evítalo cuando los archivos sean gigantescos, los consulten muchos servidores o se administren mejor con almacenamiento de objetos.

Los backups también importan. Una base con muchos BLOB crece rápido y puede hacer más lentas las copias completas. Prueba restauraciones, retención, VACUUM y espacio libre. Una escritura correcta no garantiza una estrategia de recuperación adecuada.

Manejo de errores

Los fallos habituales incluyen una fila inexistente, nombres de tabla o columna incorrectos, escritura fuera del límite, cierre prematuro o base bloqueada. Captura excepciones específicas de sqlite3, registra rowid y operación, y evita guardar contenido binario sensible en logs. Usa context managers para liberar recursos de forma predecible.

Seguridad

No confíes en tipos MIME ni extensiones enviados por usuarios. Inspecciona firmas cuando corresponda, impone límites de tamaño antes de reservar zeroblob y restringe qué filas puede abrir cada usuario. Si los datos son sensibles, protege el archivo de base, sus backups y cualquier copia temporal.

Pruebas de rendimiento

Mide cargas reales. Compara SELECT completos con lecturas incrementales, prueba distintos tamaños de bloque y observa la duración de los bloqueos. Para BLOB pequeños quizá no compense la complejidad; para valores grandes el beneficio puede ser considerable.

Lista final de buenas prácticas

Abre el BLOB con context manager, reserva con zeroblob, procesa bloques fijos, valida tamaño y hash, mantén transacciones cortas y prueba interrupciones. Con estas prácticas, sqlite3.Blob ofrece acceso binario incremental eficiente sin perder la simplicidad de SQLite.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Análisis estadístico para random.binomialvariate en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    random.binomialvariate: simula resultados binomiales

    Aprende random.binomialvariate en Python para simular éxitos, validar probabilidades y analizar escenarios binomiales con ejemplos.

    Ler mais

    Tempo de leitura: 5 minutos
    11/09/2026
    Código Python y análisis de firmas de funciones
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    inspect.signature.bind: valida argumentos de funciones

    Aprende inspect.signature.bind en Python para validar argumentos, aplicar valores predeterminados y crear APIs dinámicas seguras.

    Ler mais

    Tempo de leitura: 5 minutos
    11/09/2026
    Código Python para limpieza segura de directorios con shutil.rmtree
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    shutil.rmtree onexc: maneja errores al borrar carpetas

    Aprende shutil.rmtree con onexc en Python para eliminar directorios, tratar permisos, registrar fallos y crear limpiezas seguras.

    Ler mais

    Tempo de leitura: 7 minutos
    10/09/2026
    Gráfico de análisis de datos para statistics.kde en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    statistics.kde: estima densidades en Python

    Aprende statistics.kde en Python para estimar densidades, elegir bandwidth, comparar kernels e interpretar distribuciones con cuidado.

    Ler mais

    Tempo de leitura: 7 minutos
    10/09/2026
    Codigo y archivos gestionados con ExitStack en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    contextlib.ExitStack: gestiona recursos dinámicos

    Aprende contextlib.ExitStack en Python para gestionar recursos dinámicos, callbacks de limpieza y excepciones de forma segura.

    Ler mais

    Tempo de leitura: 4 minutos
    09/09/2026
    Desarrollador creando plantillas de texto con string.Template en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    string.Template: plantillas de texto simples y seguras

    Aprende string.Template en Python para crear textos configurables, validar campos y sustituir valores de forma clara y segura.

    Ler mais

    Tempo de leitura: 6 minutos
    09/09/2026