struct no Python: trabalhe com binário

Publicado em: 17/08/2026
Tempo de leitura: 5 minutos
A male software engineer working on code in a modern office setting.

O módulo struct no Python converte valores como inteiros, floats, booleanos e sequências de bytes para layouts binários compactos. O caminho inverso também é suportado: você recebe bytes de um arquivo, dispositivo ou conexão de rede e os interpreta conforme uma estrutura definida por uma string de formato.

Essa ferramenta é útil em protocolos, cabeçalhos de arquivos, integração com C, sensores e formatos legados. O maior risco é confiar implicitamente na plataforma. Sem prefixo, struct usa ordem de bytes, tamanhos e alinhamento nativos, que podem variar. Para intercâmbio externo, defina endianness e tamanhos explicitamente.

Primeiro pack e unpack

import struct

formato = ">Ih"
pacote = struct.pack(formato, 1_000_000, -12)
identificador, temperatura = struct.unpack(formato, pacote)

print(pacote.hex())
print(identificador, temperatura)

> seleciona big-endian e tamanhos padronizados. I representa um inteiro sem sinal de 32 bits e h um inteiro com sinal de 16 bits. O resultado de unpack() é sempre uma tupla.

Endianness

A ordem de bytes determina como os bytes mais e menos significativos são armazenados:

  • <: little-endian, tamanhos padrão e sem alinhamento automático.
  • >: big-endian, tamanhos padrão.
  • !: ordem de rede, equivalente a big-endian.
  • =: ordem nativa com tamanhos padrão e sem padding.
  • @: ordem, tamanho e alinhamento nativos.
import struct

print(struct.pack(">H", 1023).hex())  # 03ff
print(struct.pack("<H", 1023).hex())  # ff03

Em protocolos e arquivos, evite o modo nativo. Defina <, > ou ! para que o layout seja igual em todas as máquinas.

Calcule o tamanho antes de ler

calcsize() informa quantos bytes o formato exige:

import struct

CABECALHO = struct.Struct("!4sBBHI")
print(CABECALHO.size)

with open("mensagem.bin", "rb") as arquivo:
    bruto = arquivo.read(CABECALHO.size)
    if len(bruto) != CABECALHO.size:
        raise ValueError("cabeçalho incompleto")
    magia, versao, flags, tipo, tamanho = CABECALHO.unpack(bruto)

Valide comprimento antes de desempacotar. unpack() exige tamanho exato; unpack_from() precisa de pelo menos o tamanho a partir do offset.

Use Struct para formatos repetidos

A classe Struct compila a string de formato uma vez e reúne tamanho e métodos:

import struct

REGISTRO = struct.Struct("<Iff?")

payload = REGISTRO.pack(42, 18.5, 70.25, True)
identificador, x, y, ativo = REGISTRO.unpack(payload)

Os formatos recentes também são armazenados em cache pelas funções do módulo, mas um objeto nomeado documenta o protocolo e reduz repetição.

Caracteres mais usados

  • b/B: inteiro de 8 bits com/sem sinal.
  • h/H: inteiro de 16 bits.
  • i/I: inteiro padrão de 32 bits.
  • q/Q: inteiro de 64 bits.
  • e, f, d: float de 16, 32 e 64 bits.
  • ?: booleano.
  • s: sequência de bytes de tamanho fixo.
  • x: byte de padding.

No Python 3.14, F e D adicionam números complexos de precisão simples e dupla.

Strings de tamanho fixo

import struct

FORMATO = struct.Struct("!10sI")
bruto = FORMATO.pack(b"sensor-1", 123)
nome, leitura = FORMATO.unpack(bruto)
nome = nome.rstrip(b"\x00").decode("ascii")

10s é um único campo de dez bytes. Dados maiores são truncados; menores recebem zeros. Valide o comprimento antes de empacotar para não perder conteúdo silenciosamente.

pack_into evita alocação extra

Quando você já possui um bytearray, escreva diretamente:

import struct

buffer = bytearray(1024)
CABECALHO = struct.Struct("!IHH")
CABECALHO.pack_into(buffer, 0, 900, 2, 7)

identificador, versao, flags = CABECALHO.unpack_from(buffer, 0)

As funções aceitam objetos do protocolo de buffer, como bytes, bytearray e memoryview. Isso ajuda a reduzir cópias em pipelines binários.

Leia registros repetidos

iter_unpack() interpreta blocos consecutivos do mesmo tamanho:

import struct

REGISTRO = struct.Struct("<Ih")
dados = b"".join([
    REGISTRO.pack(1, 20),
    REGISTRO.pack(2, 25),
    REGISTRO.pack(3, 18),
])

for identificador, valor in REGISTRO.iter_unpack(dados):
    print(identificador, valor)

O comprimento total deve ser múltiplo do tamanho do registro. Rejeite o bloco se houver sobra, pois ela pode indicar corrupção ou versão diferente.

Protocolo com tamanho de payload

Um cabeçalho frequentemente inclui o comprimento do corpo:

import struct

HEADER = struct.Struct("!4sBI")
MAX_PAYLOAD = 10 * 1024 * 1024

header = receber_exatamente(HEADER.size)
magic, version, length = HEADER.unpack(header)

if magic != b"APP1" or version != 1:
    raise ValueError("protocolo inválido")
if length > MAX_PAYLOAD:
    raise ValueError("payload excedeu o limite")

payload = receber_exatamente(length)

Nunca aloque memória apenas com base em um tamanho fornecido pelo remetente. Aplique teto, timeout e limite de mensagens.

Integração com rede

Use ! para ordem de rede. O artigo sobre zlib no Python mostra como um corpo pode ser comprimido, mas o cabeçalho deve informar versão, flags, algoritmo e tamanho de forma inequívoca. O guia de opcode no Python reforça que números internos da VM não são um protocolo estável; defina seus próprios códigos versionados.

Alinhamento nativo

No modo @, o compilador C da plataforma pode inserir padding entre campos. Isso é útil para espelhar uma struct C dentro do mesmo ambiente, mas perigoso para arquivos portáteis.

import struct

print(struct.calcsize("@ci"))
print(struct.calcsize("@ic"))
print(struct.calcsize("=ci"))

A ordem dos campos pode mudar o tamanho no modo nativo. Em formato padrão, padding só aparece quando você o declara com x.

Faixas e struct.error

Valores fora da faixa lançam struct.error:

import struct

try:
    struct.pack("!h", 100_000)
except struct.error as erro:
    raise ValueError("valor fora de 16 bits") from erro

Valide também NaN, infinito, valores reservados e combinações de flags conforme o protocolo.

Não use struct como serializador geral

struct não guarda nomes de campos, versões ou esquema. É ideal para layouts compactos e estáveis, não para objetos arbitrários. JSON é melhor para interoperabilidade legível; bancos e formatos como Protocol Buffers oferecem evolução de esquema.

Segurança

  • Valide tamanho antes de desempacotar.
  • Defina endianness explicitamente.
  • Imponha limites a comprimentos declarados.
  • Rejeite versões e códigos desconhecidos.
  • Use timeouts em rede.
  • Não interprete padding ou bytes reservados sem regra.
  • Não use ponteiros P em dados externos.
  • Faça fuzzing do parser.

Testes recomendados

Teste limites mínimos e máximos, endian invertido, buffers curtos, bytes extras, registros incompletos, NaN, infinito, caracteres nulos, versões futuras e payloads acima do teto. Compare os bytes esperados, não apenas o round trip.

def test_header_bytes():
    assert HEADER.pack(b"APP1", 1, 5) == b"APP1\x01\x00\x00\x00\x05"

Boas práticas

  • Crie constantes Struct nomeadas.
  • Documente cada campo e unidade.
  • Inclua magia e versão.
  • Use tamanhos padrão.
  • Valide antes de alocar.
  • Use pack_into e memoryview quando cópias importarem.
  • Registre erros sem despejar dados sensíveis.

Conclusão

O struct no Python é uma ponte eficiente entre valores Python e layouts binários. Ele funciona muito bem em cabeçalhos, arquivos e protocolos, desde que ordem de bytes, tamanhos, versões e limites sejam explícitos.

Consulte a documentação oficial do struct e a documentação do protocolo de buffer. Para parametrizar versões e limites, veja configparser no Python, e para observar o parser em execução use trace no Python.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Close-up of a laptop screen with code and a coffee mug, perfect for tech abstract themes.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tarfile no Python: crie TAR seguro

    Aprenda tarfile no Python para criar TAR comprimido, inspecionar membros e extrair com filtros, limites e proteção contra path traversal.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Row of colorful office binders neatly arranged on a shelf, ideal for organization concepts.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    gzip no Python: comprima arquivos .gz

    Aprenda gzip no Python para ler e gravar .gz, criar saídas reproduzíveis, trabalhar com streams e limitar a expansão de

    Ler mais

    Tempo de leitura: 4 minutos
    17/08/2026
    Color-coded office binders organized neatly in a storage shelf, featuring labels and a striking red binder.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    lzma no Python: comprima arquivos XZ

    Aprenda lzma no Python para criar arquivos XZ, usar streams, checks, filtros e limites de memória ao descompactar dados externos.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Exquisite python skin handbag with intricate snake emblem and elegant design.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    bz2 no Python: comprima com bzip2

    Aprenda bz2 no Python para comprimir arquivos e bytes, processar fluxos em blocos e limitar a expansão de dados externos.

    Ler mais

    Tempo de leitura: 5 minutos
    16/08/2026
    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