Reading & Writing Files
Knowing open(), .read(), and .write() is the starting point, but real programs need a few more practical patterns: reading huge files without running out of memory, understanding the difference between appending and overwriting, handling text encoding correctly across operating systems, and working with binary data. This page walks through each of these, then ties them together in a complete worked example.
Reading Line-by-Line with `for line in f:`
.readlines() reads the entire file into memory and returns every line as a list before you can process any of it. For a file that's a few kilobytes, that's fine. For a multi-gigabyte log file, it can exhaust your available memory. The fix is to iterate over the file object directly — Python reads one line at a time under the hood, so memory usage stays flat no matter how large the file is.
# Loads the whole file into a list first — avoid for large files
with open("access.log", "r", encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
process(line)
# Streams one line at a time — memory usage stays constant
with open("access.log", "r", encoding="utf-8") as f:
for line in f:
process(line)Appending vs. Overwriting
Mode 'w' truncates the file the instant it's opened — any existing content is gone immediately, even before you write anything new. Mode 'a' instead moves to the end of the file and adds new content after what's already there. Mixing these up is a common source of accidentally-deleted data.
with open("log.txt", "w", encoding="utf-8") as f:
f.write("Line 1\n")
f.write("Line 2\n")
# 'w' again: the file is wiped out and starts fresh
with open("log.txt", "w", encoding="utf-8") as f:
f.write("Line A\n")
with open("log.txt", "r", encoding="utf-8") as f:
print("After overwrite:")
print(f.read())
# 'a': new content is added after the existing content
with open("log.txt", "a", encoding="utf-8") as f:
f.write("Line B\n")
with open("log.txt", "r", encoding="utf-8") as f:
print("After append:")
print(f.read())After overwrite: Line A After append: Line A Line B
Always Pass `encoding='utf-8'` Explicitly
When you don't pass an encoding argument, Python falls back to the operating system's locale-preferred encoding to decide how bytes on disk map to text characters. That default is not the same everywhere.
Platform | Typical default text encoding |
|---|---|
Windows (English/Western) |
|
Linux |
|
macOS |
|
# Portable and predictable on every platform
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("café, naïve, 日本語\n")
with open("notes.txt", "r", encoding="utf-8") as f:
print(f.read())café, naïve, 日本語
Binary Files
Text mode assumes the file contains characters and decodes bytes accordingly. Some files — images, audio, PDFs, ZIP archives — aren't text at all, and decoding them as text would corrupt the data. For these, open the file in binary mode ('rb', 'wb') and work with bytes objects instead of str. A binary copy of a file is a common example: read raw bytes in, write the same raw bytes out.
with open("photo.jpg", "rb") as source:
data = source.read()
with open("photo_copy.jpg", "wb") as destination:
destination.write(data)
print(f"Copied {len(data)} bytes")Copied 482113 bytes
Worked Example: Filtering a Log File
Here's a complete example that combines line-by-line reading, explicit encoding, and writing: it reads a log file, keeps only the lines that contain "ERROR", and writes just those lines to a new file — all without ever loading the full input file into memory at once.
input_path = "app.log"
output_path = "errors_only.log"
error_count = 0
with open(input_path, "r", encoding="utf-8") as infile, open(
output_path, "w", encoding="utf-8"
) as outfile:
for line in infile:
if "ERROR" in line:
outfile.write(line)
error_count += 1
print(f"Wrote {error_count} error lines to {output_path}")Wrote 3 error lines to errors_only.log
for line in f:streams a file one line at a time and scales to files of any size.'w'truncates immediately on open;'a'preserves existing content and appends.Always pass
encoding='utf-8'explicitly — the OS default is not guaranteed and varies between Windows and Linux/macOS.Use binary mode (
'rb'/'wb') for non-text files like images, and never combine it withencoding.