Lesson 17 — Reading Files
Estimated time: 75 minutes
- Learning Objectives
- Concepts
- Guided Walkthrough
- Challenges
- Common Mistakes & Debugging
- Key Vocabulary
Learning Objectives
By the end of this lesson you will be able to:
- Open a text file for reading using
open()andwith - Read file contents using
.read(),.readline(),.readlines() - Parse simple CSV data from a file
- Load configuration settings from a file
Concepts
Why Files?
Variables live in RAM — they exist while your program runs, then vanish when power is cut. Files live in flash memory (or on a hard drive) — they persist.
Use files for:
- High scores — remember the best score between sessions
- Configuration — store settings that shouldn’t be in code
- Logging — record sensor readings over time
- Data — question banks, word lists, colour palettes
The MicroPython Filesystem
The ESP32-S3 has a small filesystem in its flash memory. You can see and manage files in Thonny’s Files panel (View > Files). The “MicroPython device” section shows files on the ESP32.
To create a file on the ESP32:
- Write content in Thonny’s editor
- Click File > Save As
- Choose “MicroPython device” and save with the right filename
open() and File Modes
f = open("filename.txt", "r") # Open for reading
File modes:
"r"— Read. File must exist. Default mode."w"— Write. Creates new or overwrites existing file."a"— Append. Adds to end without overwriting.
The with Statement
The with statement automatically closes the file when the block ends, even if an error occurs:
# Without with (must manually close):
f = open("data.txt", "r")
content = f.read()
f.close() # Easy to forget!
# With with (cleaner, safer):
with open("data.txt", "r") as f:
content = f.read()
# File is automatically closed here
Always use with for file operations.
Reading Methods
.read() — reads the entire file as one string:
with open("data.txt", "r") as f:
all_text = f.read()
.readline() — reads one line at a time (includes \n):
with open("data.txt", "r") as f:
line1 = f.readline() # First line
line2 = f.readline() # Second line
.readlines() — reads all lines, returns a list:
with open("data.txt", "r") as f:
lines = f.readlines() # List of strings, each ending with \n
Iterating line by line (most memory-efficient):
with open("data.txt", "r") as f:
for line in f:
print(line.strip()) # strip() removes \n and spaces
.strip() — Always Strip Your Lines
When reading lines, each one ends with \n (newline character). Use .strip() to remove it:
line = "Hello World\n"
clean = line.strip() # "Hello World"
.strip() removes whitespace (spaces, tabs, newlines) from both ends.
Guided Walkthrough
Step 1: Create a Test File on the ESP32
In Thonny, create a new file and type this content:
Hello from the filesystem!
This is line 2.
This is line 3.
MicroPython is fun.
Save it to the MicroPython device as message.txt.
Step 2: Read the Whole File
# Read the entire file at once
with open("message.txt", "r") as f:
content = f.read()
print(content)
print("---")
print(f"Total characters: {len(content)}")
Step 3: Read Line by Line
with open("message.txt", "r") as f:
lines = f.readlines()
print(f"Number of lines: {len(lines)}")
for i, line in enumerate(lines):
clean = line.strip()
print(f"Line {i+1}: '{clean}'")
Step 4: Configuration File
This pattern — storing settings in a file instead of hardcoding them — is used everywhere in real software.
Create a file called config.txt on the ESP32:
led_colour=0,128,255
brightness=80
message=Hello from config!
repeat=3
Read and use it:
import machine, neopixel, time
config = {}
with open("config.txt", "r") as f:
for line in f:
line = line.strip()
if line and "=" in line: # Skip blank lines and malformed ones
key, value = line.split("=", 1) # Split at FIRST = only
config[key.strip()] = value.strip()
print("Loaded config:", config)
# Use the config
pin = machine.Pin(48, machine.Pin.OUT)
np = neopixel.NeoPixel(pin, 1)
# Parse the LED colour (stored as "R,G,B")
r, g, b = config["led_colour"].split(",")
np[0] = (int(r), int(g), int(b))
np.write()
# Show the message n times
repeat = int(config["repeat"])
msg = config["message"]
for i in range(repeat):
print(f"Message {i+1}: {msg}")
time.sleep(3)
np[0] = (0, 0, 0)
np.write()
Step 5: Reading CSV Data
Create scores.csv on the ESP32:
name,score,grade
Alice,87,B
Bob,92,A
Charlie,63,C
Diana,78,B
Parse and display it:
with open("scores.csv", "r") as f:
lines = f.readlines()
# First line is the header
headers = lines[0].strip().split(",")
print("Headers:", headers)
# Parse data rows
students = []
for line in lines[1:]: # Skip header
line = line.strip()
if line:
parts = line.split(",")
student = {
"name": parts[0],
"score": int(parts[1]),
"grade": parts[2]
}
students.append(student)
print(f"\nLoaded {len(students)} students:")
for s in students:
print(f" {s['name']:10s}: {s['score']:3d} ({s['grade']})")
# Analysis
scores = [s["score"] for s in students]
print(f"\nClass average: {sum(scores)/len(scores):.1f}")
print(f"Highest: {max(scores)}")
print(f"Lowest: {min(scores)}")
The {s['name']:10s} format spec in the f-string pads the name to 10 characters wide, making output nicely aligned.
Challenges
⭐ Core
Create a file colours.txt on the ESP32 with 6 colour names (one per line). Write a program that reads the file and picks a random colour (import random; random.choice(lines)). Print it and show a matching LED colour (you’ll need a lookup in your code for each name).
⭐⭐ Extension
Create a highscores.txt CSV file with 5 players and scores (format: name,score). Read the file, sort by score descending, and print a numbered leaderboard. Display the LED colour based on the top score: gold (255,215,0) if >90, silver (180,180,180) if >70, bronze (205,127,50) if lower.
⭐⭐⭐ Stretch
Create a quiz.txt file with 5 questions and answers in the format question|answer. Write a quiz program that reads each question, asks the user (via input()), and checks the answer (case-insensitive). Track score. After all questions, print the result and display an appropriate LED colour (green ≥80%, yellow ≥50%, red <50%).
Common Mistakes & Debugging
OSError: [Errno 2] ENOENT File not found. Check: (1) the file is saved to the ESP32, not your computer, (2) the filename is spelled correctly (case-sensitive!), (3) refresh Thonny’s file browser.
Lines have unexpected \n in them Always use .strip() when reading lines. line.strip() removes the trailing newline.
ValueError: not enough values to unpack Your .split(",") produced fewer parts than expected. Check the file format — a line might be blank or malformed.
File panel not showing your file Click the refresh/reload button in Thonny’s Files panel. If the file still doesn’t appear, it may have been saved to your computer instead of the ESP32.
Key Vocabulary
| Term | Definition |
|---|---|
| filesystem | The system that organises and stores files — the ESP32 has one in flash memory |
| open() | Built-in function that opens a file and returns a file object |
| file mode | How the file is opened: "r" read, "w" write, "a" append |
| with statement | Ensures a file is properly closed after use, even if an error occurs |
| read() | Reads entire file contents as a string |
| readlines() | Reads all lines and returns them as a list |
| strip() | Removes whitespace (including \n) from the start and end of a string |
| CSV | Comma-Separated Values — a text format for tabular data |
| parse | Extract structured data from raw text |