Skip to main content

A library for defining the structure of a binary file and then reading or writing it.

Project description

binaryfile

A library for defining the structure of a binary file and then reading or writing it.

import binaryfile

def png(b):
	b.byteorder = 'big'
	b.skip(16)
	b.uint('width', 4)
	b.uint('height', 4)
	b.uint('depth', 1)

with open('image.png', 'rb') as fh:
	data = binaryfile.read(fh, png)
print(f"Image is {data.width} pixels wide, {data.height} pixels tall, and {data.depth} bits deep.")

Getting Started

Requirements

You will need Python 3.6 or later.

Installing

Windows with Python launcher:

py -3 -m pip install binaryfile

Linux with python3-pip:

pip3 install binaryfile

How to use

If you want to read or write to a binary file, first you will need to define the file structure. You do this by writing a function that takes a single argument, which is a subclass of binaryfile.fileformat.BinarySectionBase. The file structure is then defined by calling methods on said argument:

import binaryfile
import io

# Define the file structure
def file_spec(f):
	size = f.count('size', 'text', 2)  # A two-byte unsigned integer
	f.bytes('text', size)  # A variable number of bytes

if __name__ == '__main__':
	# Read the file and print the text field
	with open('myfile.dat', 'rb') as file_handle:
		data = binaryfile.read(file_handle, file_spec)
	print(data.text.decode('utf-8'))

	# Modify the text field
	data.text += ' More Text!'.encode('utf-8')

	# Errors will throw exceptions and
	# cause the written file to be truncated,
	# so write to a memory buffer first
	modified_buffer = io.BytesIO()
	binaryfile.write(modified_buffer, data, file_spec)

	# Then write back to file
	with open('myfile.dat', 'wb') as file_handle:
		file_handle.write(modified_buffer.getvalue())

You can break the definition into reusable sections:

def subsection_spec(f):
	f.struct('position', 'fff')  # Three floats, using a format string from Python's built-in struct module

def section_spec(f):
	f.int('type', 1)  # A one-byte signed integer
	f.section('subsection1', subsection_spec)  # Three floats, as specified in subsection_spec
	f.section('subsection2', subsection_spec)

def file_spec(f):
	f.section(f'section1', section_spec)
	f.section(f'section2', section_spec)
	f.section(f'section3', section_spec)

if __name__ == '__main__':
	with open('myfile2.dat', 'rb') as file_handle:
		data = binaryfile.read(file_handle, file_spec)
	print(data.section2.subsection1.position)

And you can declare fields to be arrays and use loops:

def file_spec(f):
	f.array('positions')  # Declare "positions" to be an array
	count = f.count('count', 'positions', 4)
	for i in range(count):
		f.struct('positions', 'fff')  # Each time "positions" is used, it's the next element of the array

Configuration

Result type

By default, a file is read into a binaryfile.utils.SimpleDict, which allows you to access the fields by dot notation (e.g. foo.bar.baz). This means you cannot use names that are invalid field names in Python.

To override the result type, pass the desired type to result_type in the read call, e.g.:

binaryfile.read(fh, spec, result_type=dict)

The desired type must be a dict-like type that implements __getitem__, __setitem__ and __contains__.

Byte order

The default byte order is big-endian. You can change the endianness either by setting byteorder on the BinarySectionBase object, or in individual methods that support it. Valid byteorders are 'big' and 'little', which is also the possible values returned by sys.byteorder.

def spec(b):
	b.byteorder = 'little'
	b.int('a', 4)  # Little-endian
	b.int('b', 4, byteorder='big')  # Big-endian
	b.int('c', 4)  # Little-endian again

Automated tests

Setting up the environment

  1. Create and activate a Python virtual environment.
  2. From the project root, run ./setup.py develop to install a binaryfile package linked to the project source into the venv.

Running the tests

Make sure that the venv is active, then run the Python files in the tests folder.

License

This project is licensed under MIT License, see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

binaryfile-1.1.1.tar.gz (6.7 kB view details)

Uploaded Source

Built Distribution

binaryfile-1.1.1-py3-none-any.whl (7.0 kB view details)

Uploaded Python 3

File details

Details for the file binaryfile-1.1.1.tar.gz.

File metadata

  • Download URL: binaryfile-1.1.1.tar.gz
  • Upload date:
  • Size: 6.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/47.3.1 requests-toolbelt/0.9.1 tqdm/4.46.1 CPython/3.8.2

File hashes

Hashes for binaryfile-1.1.1.tar.gz
Algorithm Hash digest
SHA256 2a0cf259abed46eb20a750d74aa8f8c2d2064b831f758a3c242cc19fba12c81c
MD5 01d3e3119ea818e19b06c0c3a662cd8e
BLAKE2b-256 5df45e68e55380fb400d86e968fe9c2588dba160f0e66f8fcb268d99738b4a7e

See more details on using hashes here.

File details

Details for the file binaryfile-1.1.1-py3-none-any.whl.

File metadata

  • Download URL: binaryfile-1.1.1-py3-none-any.whl
  • Upload date:
  • Size: 7.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/47.3.1 requests-toolbelt/0.9.1 tqdm/4.46.1 CPython/3.8.2

File hashes

Hashes for binaryfile-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c155f9e1629d99507dec4857d757b51d7b45082a14ee5a2e9cabc221997fe7f7
MD5 01c505ebeedd54621d370d9bb4e05d03
BLAKE2b-256 8da6629fc671db519f1c781108f4c26eaea40943bd99ecbd57a83d8d4a539323

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page