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:

ModeMeaningDescription
'r'ReadDefault mode; file must exist
'w'WriteCreates new file or overwrites existing
'a'AppendAdds data to end of file
'r+'Read + WriteFile must exist
'w+'Write + ReadCreates new file or overwrites
'a+'Append + ReadAdds 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 CaseDescription
🔹 ETL PipelinesRead source files, handle missing data files gracefully
🔹 Logging SystemsWrite error logs without crashing
🔹 Config ManagementLoad .ini, .json, .yaml safely
🔹 APIs & BackendsReturn proper error codes/messages instead of breaking
🔹 ML PipelinesHandle 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)

#QuestionHint
1Difference between syntax error and exception?Syntax error = code not valid; exception = runtime error
2What are different file modes?'r', 'w', 'a', 'r+', etc.
3How does with statement work internally?Context managers → __enter__, __exit__
4Difference between FileNotFoundError and IOError?FileNotFoundError is subclass of IOError
5What is the role of finally block?Always executes (cleanup tasks)
6What are user-defined exceptions?Custom class inheriting from Exception
7How do you log exceptions in production?Use logging module
8What is raise ... from ... used for?Preserve original traceback
9What’s the difference between read(), readline(), and readlines()?Entire content vs single line vs list of lines
10Can you open a file in both read and write mode?Yes, 'r+', 'w+', 'a+'
11What happens if file isn’t closed?Memory leaks, file locks, OS errors
12Why use exception handling?To prevent crash and handle runtime errors
13How to handle multiple exceptions in one line?except (ValueError, TypeError): ...
14What is exception propagation?Exception bubbles up the call stack until caught
15Difference 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.


Pages: 1 2

Posted in

Leave a Reply

Your email address will not be published. Required fields are marked *