Python File I/O & Error Handling Explained — Complete Guide with Examples
Most useful programs need to read from files (configs, data, logs) or write to files (reports, saves, exports). Programs also need to handle errors gracefully — a missing file or invalid input shouldn’t crash your app.
What You’ll Learn
- How to read and write files safely using
withstatements - The difference between read, write, and append modes
- How to handle exceptions with
try/except/else/finally - How to work with JSON and CSV data formats
- Common file I/O and error handling mistakes to avoid
Why File I/O and Error Handling Matter
Without file I/O, your program’s data disappears when it ends. Durga Antivirus Pro writes scan logs to files, reads threat signature databases, and saves quarantine data — all using Python file I/O. DodaZIP reads source files and writes compressed archives. Error handling is equally critical — a missing file shouldn’t crash the entire application. Graceful error handling is what separates professional software from fragile scripts.
flowchart LR
A["Python Basics"] --> B["Control Flow"]
B --> C["Functions"]
C --> D["Lists & Dicts"]
D --> E["Modules & Packages"]
E --> F["File I/O & Errors"]
A:::done --> B:::done --> C:::done --> D:::done --> E:::done --> F:::current
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#2563eb,stroke:#2563eb,color:#fff
style C fill:#2563eb,stroke:#2563eb,color:#fff
style D fill:#2563eb,stroke:#2563eb,color:#fff
style E fill:#2563eb,stroke:#2563eb,color:#fff
style F fill:#2563eb,stroke:#2563eb,color:#fff
Reading Files
Think of reading a file like opening a book. You open it, read the content, and close it when done.
flowchart TB
Start[Open file] --> Mode{Mode?}
Mode -->|"r (read)"| Read[File must exist<br>read content]
Mode -->|"w (write)"| Write[Create or overwrite<br>write content]
Mode -->|"a (append)"| Append[Create or append<br>add to end]
Read --> Close[Close file]
Write --> Close
Append --> Close
Close --> Done[Done]
# Read entire file at once (small files only)
with open("data.txt", "r") as file:
content = file.read()
print(content)
# Line by line (memory efficient for large files)
with open("data.txt", "r") as file:
for line in file:
print(line.strip()) # strip() removes the newline character
# All lines as a list
with open("data.txt", "r") as file:
lines = file.readlines()
print(lines)Writing Files
# Write (overwrites existing content!)
with open("output.txt", "w") as file:
file.write("Hello, World!\n")
file.write("Second line\n")
# Append (adds to the end without overwriting)
with open("output.txt", "a") as file:
file.write("Third line\n")
# Write multiple lines
lines = ["apple\n", "banana\n", "cherry\n"]
with open("fruits.txt", "w") as file:
file.writelines(lines)File Modes
| Mode | What it does |
|---|---|
"r" | Read (default) — error if file doesn’t exist |
"w" | Write — creates or overwrites |
"a" | Append — creates if missing, adds to end |
"r+" | Read and write |
"x" | Exclusive create — error if file already exists |
"b" | Binary mode (e.g., "rb", "wb") |
The with Statement (Context Manager)
The with statement automatically closes the file when the block ends, even if an error occurs. Always use it instead of manual open()/close():
# Manual close (easy to forget)
file = open("data.txt", "r")
content = file.read()
file.close() # If you forget, the file stays open
# Automatic close (preferred!)
with open("data.txt", "r") as file:
content = file.read()
# File is closed automatically hereError Handling with try/except
Errors happen. Files get deleted, users enter invalid data, networks fail. Exception handling lets your program respond to errors gracefully instead of crashing.
try:
number = int(input("Enter a number: "))
result = 10 / number
print(f"Result: {result}")
except ValueError:
print("That's not a valid number!")
except ZeroDivisionError:
print("Can't divide by zero!")
except Exception as e:
print(f"Something went wrong: {e}")
else:
print("No errors occurred!")
finally:
print("This always runs.")
flowchart TB
Try[try block] --> Success{No error?}
Success -->|"Yes"| Else[else block]
Success -->|"No"| Except[except block]
Except --> Finally[finally block]
Else --> Finally
Finally --> Done[Continue program]
| Clause | When it runs |
|---|---|
try | Code that might fail |
except | If an error occurred |
else | If NO error occurred (optional) |
finally | Always — cleanup code (optional) |
Common Exception Types
| Exception | When it occurs |
|---|---|
ValueError | Wrong value (e.g., int("abc")) |
TypeError | Wrong type (e.g., "a" + 1) |
ZeroDivisionError | Division by zero |
FileNotFoundError | File doesn’t exist |
IndexError | List index out of range |
KeyError | Dict key not found |
Raising Exceptions
Sometimes you want to create your own errors:
def set_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
if age > 150:
raise ValueError("Age seems unrealistic")
print(f"Age set to {age}")
try:
set_age(-5)
except ValueError as e:
print(f"Error: {e}")Working with JSON
JSON is everywhere — APIs, config files, data storage. It’s the most common format for exchanging structured data.
import json
# Write Python dict to JSON file
data = {"name": "Alice", "scores": [85, 92, 78]}
with open("data.json", "w") as f:
json.dump(data, f, indent=2)
# Read JSON file back to Python dict
with open("data.json", "r") as f:
loaded = json.load(f)
print(loaded["name"]) # "Alice"Working with CSV
CSV is the standard format for spreadsheets and datasets.
import csv
# Write
with open("students.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["name", "grade"])
writer.writerow(["Alice", 85])
writer.writerow(["Bob", 92])
# Read
with open("students.csv", "r") as f:
reader = csv.reader(f)
for row in reader:
print(row) # ["name", "grade"], ["Alice", "85"], ...Common Mistakes
1. Forgetting to Close a File
f = open("data.txt", "r")
data = f.read()
# forgot f.close() — file stays openFix: Always use with open(...) as f: — it closes the file automatically.
2. Reading a File Twice Without Resetting the Cursor
with open("data.txt") as f:
content = f.read() # reads entire file
again = f.read() # empty string — cursor at end!Fix: Read once, or call f.seek(0) to reset the cursor.
3. Writing When You Meant to Append
with open("log.txt", "w") as f: # Overwrites existing log!
f.write("New entry")Fix: Use "a" (append) mode to add without overwriting.
4. Catching Too Broad an Exception
try:
result = 10 / int(user_input)
except Exception: # Catches everything, even Ctrl+C!
print("Error")Fix: Catch specific exceptions (ValueError, ZeroDivisionError).
5. Forgetting newline="" When Writing CSV
with open("data.csv", "w") as f:
writer = csv.writer(f) # Blank lines between rows!Fix: Use with open("data.csv", "w", newline="") as f:.
6. Parsing JSON Without Error Handling
data = json.loads(bad_json_string) # Crashes on malformed JSONFix: Wrap in try/except json.JSONDecodeError.
Practice Questions
1. What’s the difference between "r", "w", and "a" file modes?
"r" = read (file must exist). "w" = write (overwrites or creates). "a" = append (adds to end, creates if missing).
2. What happens if you call read() twice on the same file object?
The second call returns an empty string because the cursor is at the end. Use f.seek(0) to reset.
3. What’s the difference between json.dump() and json.dumps()?
json.dump(obj, file) writes to a file. json.dumps(obj) returns a string. Same for json.load(file) vs json.loads(string).
4. When should you use else with try/except?
The else block runs only if no exception occurred. Use it for code that should execute only on success.
Challenge: Write a program that reads a CSV file of products (name, price, quantity), calculates the total value of each product (price × quantity), and writes the results to a new CSV file with an added “total” column.
Solution
import csv
with open("products.csv", "r") as f:
reader = csv.DictReader(f)
products = list(reader)
with open("products_with_total.csv", "w", newline="") as f:
fieldnames = ["name", "price", "quantity", "total"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for p in products:
price = float(p["price"])
quantity = int(p["quantity"])
p["total"] = price * quantity
writer.writerow(p)FAQ
Try It Yourself
Run this to see JSON and error handling in action:
import json
# Simulate reading/writing (in-memory)
data = {
"users": [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 30},
]
}
json_str = json.dumps(data, indent=2)
print("=== JSON Output ===")
print(json_str)
# Error handling demo
def safe_divide(a, b):
try:
return a / b
except ZeroDivisionError:
return "Cannot divide by zero!"
print(f"\nsafe_divide(10, 2) = {safe_divide(10, 2)}")
print(f"safe_divide(10, 0) = {safe_divide(10, 0)}")Expected output:
=== JSON Output ===
{
"users": [
{
"name": "Alice",
"age": 25
},
{
"name": "Bob",
"age": 30
}
]
}
safe_divide(10, 2) = 5.0
safe_divide(10, 0) = Cannot divide by zero!Mini Project: Personal Journal App
Build a journal app that saves entries to a file:
import json
from datetime import datetime
JOURNAL_FILE = "journal.json"
def load_entries() -> list:
try:
with open(JOURNAL_FILE, "r") as f:
return json.load(f)
except FileNotFoundError:
return []
def save_entries(entries: list) -> None:
with open(JOURNAL_FILE, "w") as f:
json.dump(entries, f, indent=2)
def add_entry(text: str, entries: list) -> None:
entry = {
"date": datetime.now().strftime("%Y-%m-%d %H:%M"),
"text": text,
}
entries.append(entry)
save_entries(entries)
print("Entry saved!")
def show_entries(entries: list) -> None:
if not entries:
print("No entries yet.")
return
print("\n=== MY JOURNAL ===")
for i, entry in enumerate(entries, 1):
print(f"{i}. [{entry['date']}] {entry['text']}")
print("=" * 20)
# Try it out
journal = load_entries()
print(f"Loaded {len(journal)} existing entries.")
add_entry("Started learning Python file I/O", journal)
add_entry("Built my first journal app", journal)
show_entries(journal)Expected output:
Loaded 0 existing entries.
Entry saved!
Entry saved!
=== MY JOURNAL ===
1. [2026-06-05 11:30] Started learning Python file I/O
2. [2026-06-05 11:30] Built my first journal app
====================What’s Next
You’ve completed the core Python tutorial series! Move on to Python web frameworks.
| Topic | Description | Link |
|---|---|---|
| Django Framework | Full-stack Python web framework | Django |
| Flask Framework | Lightweight Python web framework | Flask |
| FastAPI Framework | Modern async Python framework | FastAPI |
| JavaScript | Compare with frontend development | JavaScript |
Practice tip: Extend the journal app with a search_entries(keyword) function that filters entries, and a delete_entry(index) function. Or build a contact manager that saves contacts to a CSV file.
What’s Next
Congratulations on completing this Py Io tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro