File Handling¶
Read and write files on disk. The basic recipe is the same across languages: open → read or write → close.
The open() function¶
But the right way is to use with — it automatically closes the file, even on errors:
Always use with. From now on, every example will.
File modes¶
| Mode | Meaning |
|---|---|
"r" |
Read (default). File must exist. |
"w" |
Write — overwrites existing content. Creates if missing. |
"a" |
Append to end. Creates if missing. |
"x" |
Create new file. Fails if exists. |
"r+" |
Read + write. |
"rb", "wb" |
Binary mode (images, PDFs, etc.) |
Writing to a file¶
# Write a few lines
with open("greetings.txt", "w") as f:
f.write("Hello, World!\n")
f.write("Welcome to Python.\n")
f.write("This is line 3.\n")
# Verify by reading back
with open("greetings.txt", "r") as f:
print(f.read())
Note: in the browser (Pyodide) runner, the file lives in a virtual filesystem inside your tab — it disappears when you reload.
Reading from a file¶
Three common ways:
# 1. Read everything as one string
with open("greetings.txt", "r") as f:
text = f.read()
print(repr(text))
# 2. Read all lines into a list
with open("greetings.txt", "r") as f:
lines = f.readlines()
print(lines)
# 3. Read line by line — memory-efficient for big files
print("--- line-by-line ---")
with open("greetings.txt", "r") as f:
for line in f:
print(line.rstrip()) # rstrip removes the trailing \n
Appending — add to the end¶
# Append doesn't overwrite — adds to the existing file
with open("greetings.txt", "a") as f:
f.write("Extra line 1\n")
f.write("Extra line 2\n")
# Read back
with open("greetings.txt", "r") as f:
print(f.read())
write vs writelines¶
lines = ["one\n", "two\n", "three\n"]
# writelines doesn't add newlines for you
with open("nums.txt", "w") as f:
f.writelines(lines)
with open("nums.txt", "r") as f:
print(f.read())
Working with CSV files¶
CSV = Comma-Separated Values. Use the csv module — handles edge cases (quoted commas, etc.).
import csv
# Write
rows = [
["name", "age", "city"],
["Alice", 25, "Mumbai"],
["Bob", 30, "Delhi"],
["Carol", 22, "Bangalore"],
]
with open("people.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerows(rows)
# Read
with open("people.csv", "r") as f:
reader = csv.reader(f)
for row in reader:
print(row)
Read CSV into a list of dicts with DictReader:
import csv
with open("people.csv", "r") as f:
reader = csv.DictReader(f)
for row in reader:
print(row)
print(f" Name: {row['name']}, City: {row['city']}")
Working with JSON files¶
import json
data = {
"name": "Alice",
"age": 25,
"skills": ["Python", "ML", "FastAPI"],
"active": True,
}
# Write
with open("profile.json", "w") as f:
json.dump(data, f, indent=2)
# Read
with open("profile.json", "r") as f:
loaded = json.load(f)
print(loaded)
print(loaded["skills"])
Checking if a file exists¶
from pathlib import Path
p = Path("greetings.txt")
print(p.exists()) # True
print(p.is_file()) # True
print(p.is_dir()) # False
print(p.stat().st_size) # size in bytes
os.path is the older equivalent:
Delete or rename¶
import os
# Rename
os.rename("greetings.txt", "old-greetings.txt")
print(os.listdir("."))
# Delete
os.remove("old-greetings.txt")
print(os.listdir("."))
Or with pathlib:
from pathlib import Path
# Re-create for the demo
Path("temp.txt").write_text("hello")
# Rename
Path("temp.txt").rename("temp2.txt")
# Delete
Path("temp2.txt").unlink()
print("Done")
Working with paths properly (pathlib)¶
from pathlib import Path
# Build paths cross-platform
data_dir = Path("data")
data_dir.mkdir(exist_ok=True)
file_path = data_dir / "report.txt"
# Write directly
file_path.write_text("This is a report.\nLine 2.\n")
# Read directly
print(file_path.read_text())
# Parts
print("name: ", file_path.name)
print("stem: ", file_path.stem)
print("suffix:", file_path.suffix)
print("parent:", file_path.parent)
Binary files (images, PDFs)¶
# Write some bytes
data = bytes([0, 1, 2, 3, 4, 5, 255])
with open("bin.dat", "wb") as f:
f.write(data)
# Read them back
with open("bin.dat", "rb") as f:
content = f.read()
print(content)
print(list(content))
Mini-project — log file¶
from datetime import datetime
def log(message, file="app.log"):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(file, "a") as f:
f.write(f"[{timestamp}] {message}\n")
# Log a few events
log("App started")
log("User logged in")
log("User clicked button")
log("App stopped")
# Read the log
with open("app.log") as f:
print(f.read())
Practice¶
What does this print?
Expected: second
Append to the file without losing existing content
Expected: helloworld
Quiz — Quick check¶
What you remember
Q1. Which file mode appends to the end of an existing file?
-
"r" -
"w" -
"a" -
"x"
Why:
"w"wipes the file first (destroying everything)."a"opens it for writing but positions the cursor at the end."r"is read-only.
Q2. Why use with open(...) as f: instead of f = open(...)?
- It's faster
- It auto-closes the file even if an exception occurs
- It's the only way to read
- No real difference
Why: The
withstatement guaranteesf.close()runs no matter what. Without it, an exception inside the block leaves the file open — eventually causing resource leaks.
Q3. What does json.dump(data, f) do?
- Returns a JSON string
- Writes the data as JSON to the file
f - Pretty-prints to the terminal
- Validates the JSON
Why:
dumpwrites to a file object.dumps(with thes) returns a string. Same forloadvsloadsfor reading.
Common doubts¶
What happens to my file if my program crashes before f.close()?
The OS will eventually flush the buffer and close the file when the process ends, but buffered writes may be lost and on some systems the file can stay locked. Always use with open(...) as f: — it closes the file cleanly even if an exception interrupts the block.
Why does my CSV have blank lines between rows on Windows?
Because csv.writer writes \r\n and the file is also adding \n. Fix: open the file with newline="":
When should I use \"rb\" instead of \"r\"?
Use binary mode ("rb", "wb") for any file that isn't human-readable text: images, PDFs, compressed files, audio, executables. Text mode ("r") decodes bytes into a string using an encoding and translates newlines — both of which corrupt binary data.