sqlite3.Blob: leia BLOBs sem carregar tudo na memória

Publicado em: 12/09/2026
Tempo de leitura: 5 minutos
Laptop com código digital representando dados BLOB no SQLite

sqlite3.Blob no Python permite ler e gravar partes de um campo BLOB sem carregar todo o conteúdo na memória. Esse recurso é útil quando um banco SQLite armazena imagens, documentos, arquivos compactados, modelos ou blocos binários grandes. Em vez de executar um SELECT que devolve todos os bytes de uma vez, a aplicação abre um objeto semelhante a arquivo, movimenta o cursor e acessa somente o trecho necessário.

O que é sqlite3.Blob

O objeto Blob representa um manipulador incremental para uma coluna BLOB existente. Ele é obtido com o método blobopen da conexão. A API oferece leitura, escrita, posicionamento com seek, consulta do tamanho com len e acesso por índices ou fatias. O comportamento lembra um arquivo binário, mas os dados permanecem dentro da linha da tabela SQLite. Isso reduz picos de memória e simplifica atualizações localizadas.

O recurso não cria automaticamente um BLOB de tamanho arbitrário. Para reservar espaço, a prática recomendada é inserir zeroblob com o tamanho desejado e, em seguida, abrir esse campo para escrita. O tamanho do BLOB aberto é fixo durante a sessão; tentar escrever além do limite gera erro. Se for necessário aumentar ou reduzir o conteúdo, crie outro valor com o novo tamanho e substitua a coluna.

Criando a tabela e reservando espaço

import sqlite3

con = sqlite3.connect("arquivos.db")
con.execute("CREATE TABLE IF NOT EXISTS anexos (id INTEGER PRIMARY KEY, nome TEXT, dados BLOB)")
tamanho = 1024 * 1024
cur = con.execute("INSERT INTO anexos(nome, dados) VALUES (?, zeroblob(?))", ("exemplo.bin", tamanho))
rowid = cur.lastrowid
con.commit()

zeroblob cria um valor binário preenchido com zeros sem exigir que a aplicação monte uma sequência gigantesca em Python. Isso é especialmente importante para arquivos grandes. Depois do commit, a linha existe e pode ser aberta pelo rowid. O nome da tabela e da coluna deve corresponder exatamente ao esquema usado.

Abrindo e escrevendo o BLOB

with con.blobopen("anexos", "dados", rowid, readonly=False) as blob:
    bloco = b"cabecalho-binario"
    blob.write(bloco)
    blob.seek(4096)
    blob.write(b"dados-em-outra-posicao")

O context manager fecha o manipulador mesmo quando ocorre uma exceção. Isso evita recursos abertos por mais tempo que o necessário. O primeiro write grava na posição atual, inicialmente zero. seek move o cursor para um deslocamento absoluto ou relativo, seguindo a mesma ideia dos arquivos tradicionais. Para sistemas que escrevem em blocos, escolha tamanhos consistentes, como 64 KiB ou 1 MiB, e registre quantos bytes foram efetivamente persistidos.

Lendo em partes

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

A leitura incremental é a principal vantagem. O programa pode calcular hashes, enviar dados por streaming, validar cabeçalhos ou copiar conteúdo para outro destino sem manter tudo em RAM. Em aplicações web, essa abordagem ajuda a reduzir o consumo por requisição, embora seja necessário cuidar do tempo de transação e do bloqueio do banco.

Índices e fatias

sqlite3.Blob também aceita acesso por índice. Um índice retorna um inteiro entre 0 e 255, enquanto uma fatia retorna bytes. É possível substituir uma posição ou uma fatia de tamanho compatível. Esse recurso é conveniente para corrigir cabeçalhos, flags e campos fixos em formatos binários.

with con.blobopen("anexos", "dados", rowid) as blob:
    primeiro = blob[0]
    cabecalho = blob[0:16]
    blob[0] = 0x50
    blob[1:4] = b"YTH"

A fatia atribuída precisa respeitar o espaço selecionado. Não use essa API como se fosse uma lista redimensionável. Ela modifica bytes existentes, não insere novos bytes deslocando o restante.

Transações e concorrência

SQLite trabalha com transações e bloqueios de arquivo. Um BLOB aberto para escrita mantém um contexto que pode influenciar commits e outras operações. Por isso, mantenha o manipulador aberto apenas pelo tempo necessário. Em aplicações concorrentes, use transações curtas, configure timeout adequado e trate OperationalError. Não compartilhe indiscriminadamente a mesma conexão entre threads. Consulte também o guia de SQLite com Python e o artigo sobre tratamento de exceções no Python.

Se várias rotinas podem atualizar o mesmo BLOB, estabeleça uma regra de exclusão ou uma fila de gravação. O SQLite é excelente para aplicações locais e cargas moderadas, mas não substitui um serviço de objetos distribuído. Para arquivos enormes, alta concorrência ou acesso remoto, armazenar o binário fora do banco e manter apenas caminho, hash e metadados pode ser mais simples.

Validação e integridade

Antes de abrir o BLOB, valide o rowid, o nome lógico do arquivo e a permissão do usuário. Depois da escrita, calcule um hash e compare com o valor esperado. Também é útil armazenar tamanho real, tipo MIME e checksum em colunas separadas. Assim, a aplicação detecta conteúdo truncado ou incompatível.

import hashlib

h = hashlib.sha256()
with con.blobopen("anexos", "dados", rowid, readonly=True) as blob:
    for _ in range(0, len(blob), 65536):
        h.update(blob.read(65536))
print(h.hexdigest())

Para aprofundar a leitura de arquivos e buffers, veja manipulação de arquivos no Python e pathlib no Python. A documentação oficial do módulo sqlite3 e a documentação do BLOB incremental do SQLite são referências essenciais.

Copiando um arquivo para o banco

from pathlib import Path

origem = Path("arquivo.bin")
tamanho = origem.stat().st_size
cur = con.execute("INSERT INTO anexos(nome, dados) VALUES (?, zeroblob(?))", (origem.name, tamanho))
rowid = cur.lastrowid
with origem.open("rb") as src, con.blobopen("anexos", "dados", rowid) as dst:
    while bloco := src.read(1024 * 1024):
        dst.write(bloco)
con.commit()

Esse padrão mantém a memória estável porque apenas um bloco existe por vez. Em caso de falha, execute rollback e remova a linha incompleta. Para tornar o processo retomável, registre o deslocamento já confirmado e compare os blocos gravados.

Quando usar e quando evitar

Use sqlite3.Blob quando o conteúdo já pertence naturalmente à transação do banco, quando a aplicação é local, quando o tamanho é conhecido e quando leituras ou atualizações parciais trazem benefício. Evite quando os arquivos são gigantescos, acessados por muitos servidores, entregues diretamente por CDN ou administrados melhor por um sistema de arquivos ou armazenamento de objetos.

Também considere backups. Um banco com muitos BLOBs cresce rapidamente e pode tornar cópias completas mais demoradas. Teste VACUUM, estratégia de retenção e recuperação. O artigo sobre backup de banco de dados com Python ajuda a estruturar esse cuidado.

Boas práticas finais

Abra o BLOB com context manager, reserve espaço com zeroblob, grave em blocos, valide tamanho e hash, mantenha transações curtas e nunca confie apenas no nome do arquivo. Trate erros, feche a conexão e teste interrupções. Com essas práticas, sqlite3.Blob oferece uma solução eficiente para acesso binário incremental sem sacrificar clareza ou segurança.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Análise estatística para random.binomialvariate no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    random.binomialvariate: simule distribuições binomiais

    Aprenda random.binomialvariate no Python para simular sucessos, validar probabilidades e analisar cenários binomiais com clareza.

    Ler mais

    Tempo de leitura: 6 minutos
    11/09/2026
    Código Python analisado com inspect.signature.bind
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    inspect.signature.bind: valide argumentos de funções

    Aprenda inspect.signature.bind no Python para validar argumentos, aplicar padrões e criar decorators e APIs dinâmicas com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    11/09/2026
    Código Python para limpeza segura de diretórios com shutil.rmtree
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    shutil.rmtree onexc: trate erros ao excluir pastas

    Aprenda a usar shutil.rmtree com onexc no Python para remover diretórios, tratar permissões e evitar limpezas incompletas.

    Ler mais

    Tempo de leitura: 6 minutos
    10/09/2026
    Gráfico de análise de dados para statistics.kde no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    statistics.kde: estime densidades no Python

    Aprenda statistics.kde no Python para estimar densidades, escolher bandwidth, comparar kernels e analisar distribuições com segurança.

    Ler mais

    Tempo de leitura: 8 minutos
    10/09/2026
    Código e estrutura de arquivos gerenciados com contextlib.ExitStack no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    contextlib.ExitStack: gerencie recursos dinâmicos

    Aprenda contextlib.ExitStack no Python para gerenciar vários recursos e callbacks com segurança, flexibilidade e código mais limpo.

    Ler mais

    Tempo de leitura: 5 minutos
    09/09/2026
    Desenvolvedor criando modelos de texto com string.Template no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    string.Template: templates simples e seguros

    Aprenda string.Template no Python para criar textos configuráveis, validar campos e substituir valores com segurança e clareza.

    Ler mais

    Tempo de leitura: 6 minutos
    09/09/2026