---
name: python-struct-packing-for-binary-data
description: Use when you need to serialize heterogeneous data (e.g., index integers and file offsets of different byte widths) into a compact binary format, or parse a binary file format specification that includes fixed-width field encodings.
license: CC-BY-4.0
metadata:
  edam_operation: http://edamontology.org/operation_0335
  edam_topics:
  - http://edamontology.org/topic_0003
  tools:
  - Python
  - pymzML
  - Python struct module
derived_from:
- doi: 10.1093/bioinformatics/bty046
  title: pymzml
evidence_spans:
- import sqlite3 import os from pymzml import spec
claims: []
provenance:
  collection: https://w3id.org/holobiomicslab/asb-skill/collection/metabolomics/v1
  assembled_by: scripts/collect_metabolomics_collection.py
  sources:
  - build: coll_pymzml
    doi: 10.1093/bioinformatics/bty046
    title: pymzml
  dedup_kept_from: coll_pymzml
schema_version: 0.2.0
---

# python-struct-packing-for-binary-data

## Summary

Encode and decode binary data structures in Python using the struct module to serialize index-to-offset mappings and other fixed-width fields into compact byte sequences. This skill is essential for implementing custom binary file formats like indexed gzip (igzip) where multiple heterogeneous fields must be packed into a contiguous byte stream with precise byte widths.

## When to use

You need to serialize heterogeneous data (e.g., index integers and file offsets of different byte widths) into a compact binary format, or parse a binary file format specification that includes fixed-width field encodings. Specifically, apply this skill when implementing or reverse-engineering custom headers or metadata sections embedded in gzip comments or other binary containers, where the byte layout is strictly specified (e.g., IDXLEN and OFFSETLEN fields control the width of subsequent tuples).

## When NOT to use

- Input data is already in a standard, widely-supported compressed format (e.g., .gz, .bz2, .xz) with existing library support — use those libraries instead of reimplementing struct packing.
- The binary format specification is not fully documented or is subject to change — struct packing is fragile and requires exact byte-level alignment.
- File sizes are small enough that random access or compression efficiency gains do not justify the complexity of custom binary encoding.

## Inputs

- Index-to-offset mapping tuples (e.g., list of (index: int, offset: int) pairs)
- Header metadata (magic bytes, version byte, index length, offset length)
- Binary file format specification (field order, byte widths, terminator)

## Outputs

- Packed binary header bytes (gzip comment field payload)
- Complete igzip-compliant binary structure ready for embedding in gzip container

## How to apply

Begin by defining constants for magic bytes (e.g., gzip ID1/ID2), version bytes, and length fields that control the width of subsequent data. Use Python's struct module with pack/unpack format strings to encode fixed-width fields: for example, '>B' for unsigned char, '>I' for 32-bit unsigned int, or custom widths derived from the IDXLEN and OFFSETLEN parameters. Construct the binary header by concatenating magic bytes, metadata fields, and then iterating over the data tuples, packing each index-to-offset pair with the byte widths specified in the header itself. Validate the output by comparing your generated bytes byte-for-byte against a reference hex dump or known-good file to ensure the packing order, endianness, and field widths match the specification exactly.

## Related tools

- **pymzML** (Demonstrates use of struct packing to encode and read indexed gzip headers for mzML data, supporting random access without decompressing entire files) — https://github.com/pymzml/pymzML
- **Python struct module** (Core library for pack/unpack operations on binary data with format strings specifying byte widths and endianness)

## Examples

```
import struct
magic_bytes = b'FU'
version = struct.pack('>B', 1)
idx_len = struct.pack('>B', 9)
offset_len = struct.pack('>B', 6)
pairs = [(0, 0), (100, 512), (200, 1024)]
header = magic_bytes + version + idx_len + offset_len
for idx, offset in pairs:
    header += struct.pack('>Q', idx) + struct.pack('>6s', offset.to_bytes(6, 'big'))
header += b'\x00'
```

## Evaluation signals

- Generated binary header matches the reference hex dump byte-for-byte when printed as hexadecimal.
- Header structure obeys the declared IDXLEN and OFFSETLEN widths: each subsequent index-to-offset pair occupies exactly (IDXLEN + OFFSETLEN) bytes.
- Magic bytes (e.g., 0x46 0x55 for 'F' and 'U' in igzip) appear at the correct positions in the output.
- The header terminates with a single null byte (0x00) after the final index-to-offset pair.
- Unpacking the generated bytes using the inverse struct format and reconstructing the original tuples yields the input data without loss.

## Limitations

- Struct packing requires exact knowledge of field order, byte widths, and endianness; mismatches produce silently incorrect binary output that may only be detected during parsing.
- The igzip format uses variable-width offset fields (controlled by OFFSETLEN); code must handle or validate this parameter to avoid overflow when offsets exceed the specified byte width.
- No built-in validation in Python's struct module; the programmer must compare output against a reference to detect encoding errors, as struct will not warn if fields are out of order or wrong width.

## Evidence

- [other] The igzip format encodes a custom header in the gzip comment field containing ID bytes (F and U), version byte (1), index length (9 bytes in the example), offset length (6 bytes in the example), followed by index-to-offset mapping pairs, all terminated with a zero byte (\x00).: "The igzip format encodes a custom header in the gzip comment field containing ID bytes (F and U), version byte (1), index length (9 bytes in the example), offset length (6 bytes in the example),"
- [other] Implement binary packing functions to encode index-to-offset pairs as fixed-width tuples according to OFFSETLEN specification.: "Implement binary packing functions to encode index-to-offset pairs as fixed-width tuples according to OFFSETLEN specification"
- [other] Construct the complete header by concatenating magic bytes, version, length fields, all index-to-offset pairs, and a zero-terminator (null byte).: "Construct the complete header by concatenating magic bytes, version, length fields, all index-to-offset pairs, and a zero-terminator (null byte)"
- [other] Compare generated binary output byte-for-byte against the hex dump reference to verify correctness of header encoding.: "Compare generated binary output byte-for-byte against the hex dump reference to verify correctness of header encoding"
- [readme] One of the features of pymzML is the ability to (create) and read indexed gzip which allows mzML file sizes to reach the levels of the original RAW format: "One of the features of pymzML is the ability to (create) and read indexed gzip which allows mzML file sizes to reach the levels of the original RAW format"
