struct no Python: dados binários

Publicado em: 28/08/2026
Tempo de leitura: 5 minutos
Chic portrait of a woman wearing trendy sunglasses reflecting numbers, captured in a modern setting.

O módulo struct converte valores Python em sequências de bytes e reconstrói valores a partir de buffers binários. Ele é usado em protocolos de rede, cabeçalhos de arquivos, dispositivos, bancos binários, memória compartilhada e integração com programas escritos em C. A API trabalha com strings de formato que descrevem tipo, tamanho, alinhamento e ordem de bytes.

Usar struct exige precisão. Um formato incorreto pode interpretar bytes válidos como valores absurdos, cortar dados ou abrir espaço para consumo excessivo. Defina um layout documentado, valide tamanhos antes de desempacotar e nunca confie em contagens ou offsets vindos de arquivos e conexões.

O primeiro pack e unpack

pack() recebe um formato e valores; unpack() faz o caminho inverso.

import struct

dados = struct.pack("!HI", 2, 4096)
versao, tamanho = struct.unpack("!HI", dados)
print(versao, tamanho)

O prefixo ! usa ordem de rede, equivalente a big-endian e tamanhos padronizados.

Strings de formato

Caracteres comuns incluem b e B para inteiros de 8 bits, h/H para 16 bits, i/I para inteiros, q/Q para 64 bits, f e d para ponto flutuante, ? para booleano, s para bytes de tamanho fixo e x para padding.

Documente o significado de cada campo fora da string. Um formato compacto sem nomes é difícil de revisar.

Endianness

Os prefixos controlam ordem e alinhamento: > é big-endian, < é little-endian, ! é rede, = usa ordem nativa com tamanhos padrão e @ usa layout nativo completo.

little = struct.pack("<I", 0x12345678)
big = struct.pack(">I", 0x12345678)
print(little.hex(), big.hex())

Protocolos persistentes devem escolher ordem explícita. Não use @ quando dados precisam circular entre arquiteturas.

calcsize

calcsize() informa quantos bytes um formato ocupa.

FORMATO = "!4sBHI"
TAMANHO = struct.calcsize(FORMATO)

Use esse valor para validar buffers, calcular offsets e evitar números mágicos.

Bytes de tamanho fixo

O especificador Ns representa exatamente N bytes.

cabecalho = struct.pack("!4sI", b"DATA", 10)
magic, tamanho = struct.unpack("!4sI", cabecalho)

Se a entrada for menor, pack() completa com zeros; se for maior, corta. Valide comprimento antes de empacotar para não perder informação silenciosamente.

Strings e encoding

struct não codifica texto. Converta strings explicitamente.

nome = "ação".encode("utf-8")
if len(nome) > 32:
    raise ValueError("nome grande demais")
bloco = struct.pack("!32s", nome)

Ao decodificar, remova padding apenas conforme o protocolo e use o encoding correto.

unpack_from

unpack_from() lê valores de um buffer a partir de um offset sem criar um slice.

versao, flags = struct.unpack_from("!BB", buffer, 4)

Verifique se offset + calcsize(formato) cabe no buffer.

pack_into

pack_into() grava em um buffer mutável existente, como bytearray, memoryview ou mmap.

buffer = bytearray(16)
struct.pack_into("!I", buffer, 0, 123)

Essa técnica evita alocações repetidas em loops, mas exige controle rigoroso de offsets e concorrência.

iter_unpack

iter_unpack() percorre registros de tamanho fixo.

FORMATO = "!Ih"
for identificador, valor in struct.iter_unpack(FORMATO, dados):
    processar(identificador, valor)

O tamanho total do buffer precisa ser múltiplo do tamanho do registro.

Registros com tamanho variável

Para payloads variáveis, use um cabeçalho fixo com comprimento e leia o corpo separadamente.

HEADER = "!I"
tamanho = struct.unpack(HEADER, receber_exato(4))[0]
if tamanho > 1_000_000:
    raise ValueError("payload grande demais")
payload = receber_exato(tamanho)

O limite precisa ser aplicado antes da alocação.

Inteiros com sinal

Formatos minúsculos normalmente representam inteiros com sinal; maiúsculos, sem sinal. Valores fora do intervalo geram struct.error.

Valide domínio na camada da aplicação. Um valor tecnicamente representável pode ser inválido para o protocolo.

Ponto flutuante

f representa precisão simples e d, dupla. Resultados podem conter arredondamento, infinito e NaN.

Não use float binário para dinheiro ou contadores exatos. Defina escala inteira ou representação decimal no protocolo.

Booleanos

O formato ? serializa valores booleanos. Ao desempacotar, qualquer byte diferente de zero é verdadeiro conforme a convenção.

Se o protocolo exige apenas 0 ou 1, valide o byte bruto antes ou use B e aplique a regra explicitamente.

Padding e alinhamento

O modo nativo @ pode inserir padding para reproduzir estruturas C. O layout varia conforme arquitetura e compilador.

Para arquivos e rede, prefira <, > ou !. Use layout nativo apenas quando integrar com a ABI local e tiver testes por plataforma.

Integração com mmap

unpack_from() pode ler diretamente de um arquivo mapeado.

import mmap

with mmap.mmap(arquivo.fileno(), 0, access=mmap.ACCESS_READ) as mapa:
    magic, versao = struct.unpack_from("!4sH", mapa, 0)

Veja mmap no Python para lifecycle, alinhamento e sincronização.

Integração com sockets

TCP é um fluxo; um recv() pode retornar menos bytes que o necessário. Crie uma função que receba exatamente o cabeçalho antes de chamar unpack().

Consulte socket no Python para framing e timeouts.

Classe Struct

Quando o mesmo formato é usado repetidamente, compile-o com struct.Struct.

CABECALHO = struct.Struct("!4sBHI")
bloco = CABECALHO.pack(b"DATA", 1, 0, 128)
campos = CABECALHO.unpack(bloco)

Isso centraliza o formato e pode reduzir overhead em loops.

Layouts versionados

Inclua magic bytes e versão no início do formato. O parser pode selecionar o layout correto e rejeitar versões desconhecidas.

Adicione campos novos de forma compatível ou crie uma nova versão. Não altere silenciosamente o significado de bytes existentes.

Checksums

Um checksum ajuda a detectar corrupção, mas não fornece autenticidade contra um atacante.

Para segurança, use MAC ou assinatura criptográfica apropriada e cubra cabeçalho e payload.

Offsets e overflow lógico

Python possui inteiros grandes, mas offsets calculados podem ultrapassar o buffer ou gerar alocações enormes.

fim = offset + quantidade * tamanho_item
if quantidade > LIMITE or fim > len(buffer):
    raise ValueError("estrutura inválida")

Valide cada operação antes de criar slices ou listas.

Dados não confiáveis

unpack() não executa código, mas um parser inseguro pode consumir CPU e memória ou acessar índices inválidos.

Limite profundidade, contagens, comprimentos e tempo. Faça parsing em processo isolado quando o formato e o risco justificarem.

Exceções

Erros de formato, tamanho ou intervalo geram struct.error.

try:
    campos = struct.unpack(FORMATO, bloco)
except struct.error as erro:
    raise ValueError("registro binário inválido") from erro

Não exponha dados binários completos em logs.

Testes

Teste valores mínimos e máximos, zero, números negativos, endianness, NaN, padding, buffers curtos, campos extras, versões desconhecidas e arquivos truncados.

Use vetores conhecidos gerados por outra linguagem para confirmar interoperabilidade.

Erros comuns

Os erros mais frequentes são usar layout nativo em arquivo portátil, esquecer calcsize(), truncar strings silenciosamente, chamar unpack() com tamanho errado, confiar em comprimentos externos, usar float para valores exatos e presumir que uma chamada de socket entrega um registro completo.

Conclusão

struct é a ponte entre valores Python e layouts binários compactos. Escolha endianness explícita, centralize formatos, valide buffers e use cabeçalhos versionados.

Consulte a documentação oficial de struct, o guia de mmap no Python e o artigo de socket no Python.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    A young girl exploring a library's card catalog, symbolizes research and curiosity.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    mmap no Python: arquivos na memória

    Aprenda mmap no Python para mapear arquivos, buscar bytes, editar regiões, compartilhar memória, usar offsets e evitar erros de sincronização.

    Ler mais

    Tempo de leitura: 7 minutos
    28/08/2026
    Close-up of a hand pointing at audio editing software on a monitor in a recording studio.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    importlib.metadata: versões e plugins

    Aprenda importlib.metadata no Python para consultar versões, requisitos, arquivos, distribuições, entry points e plugins sem importar pacotes.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    Neatly arranged binders and magazines on library shelves showcasing organization.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    importlib.resources: leia arquivos de pacotes

    Aprenda importlib.resources no Python para ler templates, dados e arquivos de pacotes com Traversable, files e as_file em wheels e

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    runpy no Python: execute módulos e scripts

    Aprenda runpy no Python para executar módulos e scripts, controlar __main__, run_path, alter_sys, namespaces, testes e isolamento.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    A laptop screen showing a code editor with visible programming code in a dimly lit environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pkgutil no Python: descubra pacotes

    Aprenda pkgutil no Python para listar módulos, percorrer pacotes, descobrir plugins, consultar importers e ler recursos com segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    27/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    modulefinder no Python: descubra imports

    Aprenda modulefinder no Python para descobrir imports, dependências transitivas, módulos ausentes, paths, plugins e limitações da análise estática.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026