Here we are with a complete, step-by-step Python tutorial on
📘 File Handling + Exception Handling (Basic → Advanced → Real-World → Interview-Ready)
We’ll go from beginner-level ideas to advanced, industry-grade usage — with examples, visual thinking, and coding exercises you can try.
🧩 PART 1: FILE HANDLING IN PYTHON
🎯 What is File Handling?
File handling in Python lets you store, read, and manipulate data permanently — beyond a program’s runtime.
👉 Think of it as your program’s ability to:
- Save user data (e.g. logs, settings, or reports)
- Read configuration files
- Process large datasets from
.csv,.json,.txt, etc.
In short: File handling bridges your code and the real world.
🗂️ 1. Opening and Closing Files
Python uses the built-in open() function.
file = open("data.txt", "r") # "r" = read mode
content = file.read()
print(content)
file.close()
Modes of Opening a File:
| Mode | Meaning | Description |
|---|---|---|
'r' | Read | Default mode; file must exist |
'w' | Write | Creates new file or overwrites existing |
'a' | Append | Adds data to end of file |
'r+' | Read + Write | File must exist |
'w+' | Write + Read | Creates new file or overwrites |
'a+' | Append + Read | Adds data if file exists |
✅ Best Practice: Use with (Context Manager)
When using with, the file auto-closes, even if an error occurs.
with open("data.txt", "r") as file:
content = file.read()
print(content)
# file is automatically closed here
💡 Why it’s important:
Avoids memory leaks and locks — used everywhere in production code.
🧠 2. Reading Files
a. Read entire file:
with open("data.txt", "r") as f:
print(f.read())
b. Read line by line:
with open("data.txt", "r") as f:
for line in f:
print(line.strip())
c. Read into a list:
with open("data.txt", "r") as f:
lines = f.readlines()
print(lines)
✍️ 3. Writing Files
a. Overwrite file:
with open("newfile.txt", "w") as f:
f.write("Hello, World!\n")
f.write("Welcome to Python!")
b. Append data:
with open("newfile.txt", "a") as f:
f.write("\nAppended line.")
🧾 4. Working with File Paths (os and pathlib)
import os
from pathlib import Path
# Check existence
print(os.path.exists("data.txt"))
# Using Pathlib
p = Path("data.txt")
if p.exists():
print(p.resolve()) # full path
📦 5. Working with Different File Types
a. CSV
import csv
with open("data.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["Name", "Age"])
writer.writerow(["Rajeev", 30])
# Reading
with open("data.csv", "r") as f:
reader = csv.reader(f)
for row in reader:
print(row)
b. JSON
import json
data = {"name": "Rajeev", "skills": ["Python", "Spark"]}
with open("data.json", "w") as f:
json.dump(data, f)
with open("data.json", "r") as f:
loaded = json.load(f)
print(loaded)
⚡ PART 2: EXCEPTION HANDLING
🎯 What is Exception Handling?
When your code crashes — e.g., file not found, zero division — that’s an exception.
Python lets you catch and handle such errors gracefully without stopping the program.
🧩 1. The try...except Block
try:
x = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero!")
🧩 2. Multiple Exceptions
try:
val = int("abc")
except ValueError:
print("Conversion failed.")
except ZeroDivisionError:
print("Divide by zero error.")
🧩 3. Using else and finally
try:
num = int(input("Enter number: "))
except ValueError:
print("That's not a number!")
else:
print("No exception occurred.")
finally:
print("Always runs (cleanup, close DB connections, etc.)")
🧩 4. Catching All Exceptions (Not Always Recommended)
try:
risky_code()
except Exception as e:
print(f"Error occurred: {e}")
Used in production logging systems to prevent application crash.
🧩 5. Raising Exceptions
You can raise errors manually:
def withdraw(amount):
if amount < 0:
raise ValueError("Amount cannot be negative!")
withdraw(-10)
🧩 6. Custom Exception Classes (Advanced)
Used widely in enterprise projects to define app-specific errors.
class InsufficientBalanceError(Exception):
pass
def withdraw(balance, amount):
if amount > balance:
raise InsufficientBalanceError("Not enough balance!")
return balance - amount
try:
withdraw(100, 150)
except InsufficientBalanceError as e:
print(e)
🧩 7. Combining File + Exception Handling
try:
with open("nonexistent.txt", "r") as f:
data = f.read()
except FileNotFoundError:
print("File not found. Creating one now...")
with open("nonexistent.txt", "w") as f:
f.write("Auto-created file")
This is very common in logging, ETL, and data pipeline systems.
🏢 INDUSTRY USE CASES
| Use Case | Description |
|---|---|
| 🔹 ETL Pipelines | Read source files, handle missing data files gracefully |
| 🔹 Logging Systems | Write error logs without crashing |
| 🔹 Config Management | Load .ini, .json, .yaml safely |
| 🔹 APIs & Backends | Return proper error codes/messages instead of breaking |
| 🔹 ML Pipelines | Handle missing dataset or corrupted file scenarios |
🧠 ADVANCED CONCEPTS
1. Exception Chaining (raise ... from ...)
Useful to trace root cause in complex codebases.
try:
int("abc")
except ValueError as e:
raise RuntimeError("Parsing failed") from e
2. Context Managers (Custom with)
You can define your own with logic using __enter__ and __exit__.
class FileHandler:
def __enter__(self):
self.file = open("sample.txt", "w")
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
with FileHandler() as f:
f.write("Auto-managed file!")
Used widely in database transactions, network connections, file locks, etc.
3. Logging Instead of Print
Instead of printing exceptions, we log them:
import logging
logging.basicConfig(filename='app.log', level=logging.ERROR)
try:
1/0
except Exception as e:
logging.error("Error occurred", exc_info=True)
This is industry-standard for monitoring and debugging production systems.
🎓 INTERVIEW QUESTIONS (With Hints)
| # | Question | Hint |
|---|---|---|
| 1 | Difference between syntax error and exception? | Syntax error = code not valid; exception = runtime error |
| 2 | What are different file modes? | 'r', 'w', 'a', 'r+', etc. |
| 3 | How does with statement work internally? | Context managers → __enter__, __exit__ |
| 4 | Difference between FileNotFoundError and IOError? | FileNotFoundError is subclass of IOError |
| 5 | What is the role of finally block? | Always executes (cleanup tasks) |
| 6 | What are user-defined exceptions? | Custom class inheriting from Exception |
| 7 | How do you log exceptions in production? | Use logging module |
| 8 | What is raise ... from ... used for? | Preserve original traceback |
| 9 | What’s the difference between read(), readline(), and readlines()? | Entire content vs single line vs list of lines |
| 10 | Can you open a file in both read and write mode? | Yes, 'r+', 'w+', 'a+' |
| 11 | What happens if file isn’t closed? | Memory leaks, file locks, OS errors |
| 12 | Why use exception handling? | To prevent crash and handle runtime errors |
| 13 | How to handle multiple exceptions in one line? | except (ValueError, TypeError): ... |
| 14 | What is exception propagation? | Exception bubbles up the call stack until caught |
| 15 | Difference between try/except and assert? | assert used for debugging/test checks |
🧩 MINI PROJECT: Safe File Reader
import os
def safe_read(filepath):
try:
with open(filepath, 'r') as f:
return f.read()
except FileNotFoundError:
print(f"{filepath} not found, creating empty file.")
with open(filepath, 'w') as f:
f.write("") # create empty file
return ""
except PermissionError:
print("No permission to read this file.")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
finally:
print("Operation complete.")
# Try it
data = safe_read("demo.txt")
✅ Realistic pattern for data pipelines, config readers, and system utilities.
Leave a Reply