Skip to Content
Course content

94: Reading and Writing Binary Files

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, we've mostly dealt with text files. Text files are great because you can open them in Notepad or VS Code and actually read what's inside. But in the professional world, you'll often encounter binary files—things like images, compiled bytecode, or custom save-game formats. These aren't meant for humans; they're meant for the machine.

The biggest difference is that while text files handle strings, binary files handle bytes. If you try to treat a binary file like a text file, you'll end up with a mess of weird characters and likely a crashed program. Today, I want to show you how to actually structure data for a binary file using a small example: a player profile for a game.

Defining our binary structure

When we write to a binary file, we can't just "print" variables. We have to decide exactly how many bytes each piece of data takes up. For this, I'm going to use the struct module. It's a bit old-school, but it's the standard way to pack Python values into C-style bytes.

I want to save a player's health (an integer) and their level (an integer). In struct language, an integer is represented by 'i'. So, two integers would be 'ii'.

import struct

health = 85
level = 12

# 'ii' means two integers
binary_data = struct.pack('ii', health, level)
print(binary_data) 
# Output looks like: b'U\x05\x00\x00\x0c\x00\x00\x00'

The "TypeError" I always hit

Now, I want to add the player's name to this file. My first instinct is usually to just pack the name along with the numbers. I'll try to write it all to a file using 'wb' (write binary) mode.

player_name = "Aragorn"

with open("player.dat", "wb") as f:
    f.write(binary_data)
    f.write(player_name) # I'm making a mistake here...

If you run this, Python will scream at you: TypeError: a bytes-like object is required, not 'str'. I've lost count of how many times I've forgotten this. In binary mode, Python refuses to guess how to turn your string into bytes. You have to be explicit. I need to encode() the string first.

Here is the corrected version:

player_name = "Aragorn"

with open("player.dat", "wb") as f:
    f.write(binary_data)
    f.write(player_name.encode('utf-8')) 

Getting the data back out

Reading binary files is where things get tricky because the file doesn't tell you where one piece of data ends and the next begins. You have to read the exact number of bytes you wrote.

Since I used 'ii', and a standard integer is 4 bytes, I know the first 8 bytes are my stats. Everything after that is the name.

with open("player.dat", "rb") as f:
    # Read the first 8 bytes for health and level
    stats_bytes = f.read(8)
    health, level = struct.unpack('ii', stats_bytes)
    
    # Read the rest of the file for the name
    name_bytes = f.read()
    player_name = name_bytes.decode('utf-8')

print(f"Player: {player_name}, HP: {health}, Lvl: {level}")

It's a bit more manual than using JSON or a database, but it's incredibly fast and results in much smaller files. Just remember: when you're in 'rb' or 'wb' mode, everything must be bytes. No exceptions.




📋 Practical Task

Exercise: Building a Binary High-Score Table

Your task is to create a program that saves a list of high scores to a binary file. Each entry should consist of a score (an integer) and a player ID (an integer).

  • Create a list of tuples containing at least three scores, e.g., [(1500, 1), (1200, 2), (900, 3)].
  • Write these to a file named scores.bin using the struct module. Use the format 'ii' for each pair.
  • Write a separate function to read the scores.bin file and print the scores back out as a list of tuples.
  • Challenge: Ensure your reading loop continues until the end of the file is reached, since you won't know how many scores are in the file beforehand.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.