💾 DevAscent Academy • Core Python Textbook Series

Unit 10: File Handling in Python

The definitive guide to persistent data storage in Python. Learn how data transitions from volatile RAM to permanent disk storage, master file access modes (r, w, a, x), read and write text files efficiently, eliminate memory leaks using the with open() context manager, and manipulate structured real-world data formats like CSV and JSON.

Curriculum Level 1st Year BCA / B.Tech / Diploma
Unit Code PY-110 (Data Persistence)
Content Balance 50% Theory • 30% Code • 20% Flowcharts
Target Standard University Exam & Practical Ready
📐 Formula Verified: 50% Comprehensive Theory 30% Verified Code 20% Visual Flowcharts
1

Introduction to File Handling: Volatile Memory vs. Persistent Storage

📌 What is a File & What is File Handling? (Formal Definition)

A file is a named location stored on a non-volatile secondary storage medium (such as an SSD or Hard Disk) that stores a sequence of related bytes or characters for future retrieval.
File Handling refers to the mechanism by which a Python program interacts with the host operating system to create, open, read, modify, append, and close files on disk storage.

📐 FLOWCHART 1: VOLATILE RAM VS. NON-VOLATILE DISK STORAGE Why File Handling is Mandatory
⚡ Primary Memory (RAM)
Variables, lists, and dictionaries live in RAM. Extremely fast, but VOLATILE! As soon as your Python program exits or power cuts off, all data is permanently wiped out!
➔ Save to File ➔
💾 Secondary Storage (SSD / HDD)
Files on disk are NON-VOLATILE and permanent. Saved data survives power shutdowns, operating system restarts, and can be shared with other software!
📝 The Whiteboard vs. Notebook Analogy: Think of your computer's RAM like a classroom whiteboard: you can quickly write math problems on it, but at the end of class, the professor erases the board and everything vanishes.
A file on your hard disk is like your paper notebook: whatever you write in ink remains safely preserved forever, ready to read tomorrow or next year!

Text Files vs. Binary Files (Comparison Table)

Feature Text Files (.txt, .csv, .json, .py) Binary Files (.png, .mp3, .pdf, .exe)
Encoding Sequence of human-readable characters encoded in UTF-8 or ASCII. Raw stream of bytes (0s and 1s) without character encoding.
Line Terminators Has end-of-line characters (\n or \r\n). No line delimiters; continuous byte stream.
Readability Can be opened and edited in Notepad or VS Code directly. Shows gibberish/corrupted symbols if opened in a text editor.
Python Mode "r", "w", "a" "rb", "wb", "ab"
2

Opening and Closing Files: Syntax, Handles, and Resource Management

📌 The Built-in `open()` Function

In Python, you interact with files using the built-in open() function. It requests the operating system to allocate a file descriptor (file handle) and returns a file stream object:

file_object = open(file_name, access_mode, encoding="utf-8")

The 3 Critical Parameters of `open()`

Why Must You ALWAYS Close Files? (The Danger of Forgetting `close()`)

Every time you open a file, the operating system dedicates system resources (file locks, memory buffers). Calling file.close() is mandatory for three reasons:

  1. Buffer Flushing: Python buffers written data in RAM before flushing it to physical disk. If your program terminates unexpectedly before calling close(), your written text might never reach the disk and is lost forever!
  2. File Locking in Windows: While open, the OS locks the file. Other programs (or even another function in your own Python script) will be blocked with an error if they try to access or delete it.
  3. Operating System Resource Exhaustion: Operating systems limit the number of open file handles per process. Leaving thousands of files unclosed leads to OSError: Too many open files.
🐍 01_manual_open_and_close.py
# Step 1: Open file in write mode ('w')
file_handle = open("sample_demo.txt", "w", encoding="utf-8")

# Step 2: Write text data to the file
file_handle.write("DevAscent Academy - Unit 10 File Handling\n")
file_handle.write("Learning Python persistent storage step by step!\n")

# Step 3: Explicitly close the file to flush buffer to disk
file_handle.close()

print("File written and closed successfully!")
print("Is the file closed?:", file_handle.closed)
Terminal Output
File written and closed successfully! Is the file closed?: True
3

File Access Modes: r, w, a, and x (The Decision Matrix)

📐 FLOWCHART 2: FILE MODE SELECTION DECISION TREE How to Choose the Right Mode
Do you only want to READ?
➔ Use 'r' (Read Mode)
Raises FileNotFoundError if file is missing.
OR
Do you want to APPEND to existing text?
➔ Use 'a' (Append Mode)
Preserves old data; writes at file end.
▼ If Writing New Files ▼
Overwrite / Wipe existing content?
➔ Use 'w' (Write Mode)
WARNING: Erases all previous data silently!
OR
Safe Create (NEVER overwrite)?
➔ Use 'x' (Exclusive Mode)
Fails with FileExistsError if file already exists!
Mode Name If File Already Exists? If File Does NOT Exist? Initial File Pointer Position
"r" Read Opens file for reading. Raises FileNotFoundError Beginning of file (Index 0)
"w" Write OVERWRITES (Truncates to 0 bytes!) Creates a brand new file Beginning of file (Index 0)
"a" Append PRESERVES existing content Creates a brand new file End of file (EOF)
"x" Exclusive Raises FileExistsError Creates a brand new file Beginning of file (Index 0)
"r+" Read + Write Opens for both reading and writing. Raises FileNotFoundError Beginning of file (Index 0)
"w+" Write + Read Overwrites and allows reading. Creates a brand new file Beginning of file (Index 0)
🐍 02_mode_differences_demo.py
# 1. Overwriting with 'w'
with open("notes.txt", "w", encoding="utf-8") as f:
    f.write("Line 1: Initial content.\n")

# 2. Appending with 'a' (adds to end without destroying Line 1)
with open("notes.txt", "a", encoding="utf-8") as f:
    f.write("Line 2: Appended message.\n")

# 3. Reading back with 'r'
with open("notes.txt", "r", encoding="utf-8") as f:
    content = f.read()

print("Current contents of notes.txt:")
print(content)

# 4. Exclusive creation with 'x' (catches existing file safely)
try:
    with open("notes.txt", "x", encoding="utf-8") as f:
        f.write("This will fail because notes.txt already exists!")
except FileExistsError:
    print("Safe Catch: notes.txt already exists, 'x' mode prevented accidental overwrite!")
Terminal Output
Current contents of notes.txt: Line 1: Initial content. Line 2: Appended message. Safe Catch: notes.txt already exists, 'x' mode prevented accidental overwrite!
4

Reading Files: read(), readline(), readlines(), and Memory Efficiency

📐 FLOWCHART 3: THE 3 FILE READING METHODS IN PYTHON Memory & Return Types
1. file.read()
Reads entire file into one single string. Fast for small files, but crashes RAM on multi-gigabyte files!
➔
2. file.readline()
Reads exactly one single line up to the next \n. Ideal for line-by-line processing.
➔
3. file.readlines()
Reads all lines into a Python list of strings: ['Line 1\n', 'Line 2\n'].
🐍 03_reading_methods.py
# Setup dummy file for demonstration
with open("students.txt", "w", encoding="utf-8") as f:
    f.write("101,Rahul Sharma,BCA\n102,Pooja Verma,B.Tech\n103,Amit Kumar,BCA\n")

# Method 1: read() -> Entire file as a single string
with open("students.txt", "r", encoding="utf-8") as f:
    full_text = f.read()
    print("--- 1. read() Output (Single String) ---")
    print(full_text)

# Method 2: readlines() -> List of string lines
with open("students.txt", "r", encoding="utf-8") as f:
    lines_list = f.readlines()
    print("--- 2. readlines() Output (List) ---")
    print(lines_list)

# Method 3: BEST PRACTICE for Big Files -> Direct Loop Iteration
print("\n--- 3. Best Practice: Memory-Efficient for-loop ---")
with open("students.txt", "r", encoding="utf-8") as f:
    for line_no, line in enumerate(f, start=1):
        clean_line = line.strip()  # removes trailing newline '\n'
        print(f"Line {line_no}: {clean_line}")
Terminal Output
--- 1. read() Output (Single String) --- 101,Rahul Sharma,BCA 102,Pooja Verma,B.Tech 103,Amit Kumar,BCA --- 2. readlines() Output (List) --- ['101,Rahul Sharma,BCA\n', '102,Pooja Verma,B.Tech\n', '103,Amit Kumar,BCA\n'] --- 3. Best Practice: Memory-Efficient for-loop --- Line 1: 101,Rahul Sharma,BCA Line 2: 102,Pooja Verma,B.Tech Line 3: 103,Amit Kumar,BCA
5

The Gold Standard: Using `with open()` (Context Managers)

📌 What is a Context Manager & Why is `with` Mandatory in Modern Python?

In older Python tutorials, programmers wrote f = open(...) and f.close(). However, if an error occurred in the middle (e.g. ZeroDivisionError, ValueError), the program would crash before reaching f.close(), leaving the file locked in RAM forever!
The with statement introduces a Context Manager (implementing the __enter__ and __exit__ protocol). It guarantees that the file is closed automatically the exact moment execution leaves the indented block, even if an unhandled exception or crash happens!

📐 FLOWCHART 4: THE with open() CONTEXT MANAGER LIFECYCLE Fail-Safe Cleanup Guarantee
1. Enter Block
with open('file.txt', 'r') as f: runs __enter__. File is safely opened.
➔
2. Execute Work
Your indented statements run (reading, parsing, calculating).
➔
3. Automatic Exit
Python runs __exit__. File is closed automatically! No leaks, even on crash.
🐍 04_context_manager_proof.py
# Demonstrating automatic closure after the with block
with open("autoclose_test.txt", "w", encoding="utf-8") as file:
    file.write("Testing automatic closure!\n")
    print("Inside the 'with' block: Is file closed? ->", file.closed)

# Notice we are now OUTSIDE the with block (unindented)
print("Outside the 'with' block: Is file closed? ->", file.closed)
Terminal Output
Inside the 'with' block: Is file closed? -> False Outside the 'with' block: Is file closed? -> True
6

Working with Structured Data: CSV Files (`csv` Module)

📌 What is a CSV File?

CSV (Comma-Separated Values) is a plain text tabular data format where each line represents a data record, and each field within that record is separated by a delimiter (typically a comma ,). It is the universal standard for exporting tables between Python, Microsoft Excel, and SQL databases.
Python provides the dedicated built-in csv module to handle row parsing, commas inside quoted text, and header mapping automatically.

🐍 05_csv_handling.py
import csv

# --- 1. Writing to a CSV File using csv.writer ---
student_records = [
    ["Roll No", "Name", "Marks", "City"],
    [101, "Aman Gupta", 88, "Delhi"],
    [102, "Neha Sharma", 92, "Jaipur"],
    [103, "Karan Joshi", 76, "Mumbai"]
]

# newline='' prevents blank lines on Windows systems
with open("students.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerows(student_records)
print("CSV File written successfully!")

# --- 2. Reading a CSV File using csv.DictReader (Header-aware!) ---
print("\nReading CSV using csv.DictReader:")
with open("students.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(f"  Student #{row['Roll No']} -> {row['Name']} ({row['City']}) Scored: {row['Marks']}")
Terminal Output
CSV File written successfully! Reading CSV using csv.DictReader: Student #101 -> Aman Gupta (Delhi) Scored: 88 Student #102 -> Neha Sharma (Jaipur) Scored: 92 Student #103 -> Karan Joshi (Mumbai) Scored: 76
7

Working with Hierarchical Data: JSON Files (`json` Module)

📌 What is JSON? (JavaScript Object Notation)

JSON (JavaScript Object Notation) is a lightweight, human-readable data interchange format. It is the de facto global standard for communication between mobile apps, web servers, and cloud REST APIs. JSON maps directly to Python's built-in data types (Python Dictionaries ➔ JSON Objects, Python Lists ➔ JSON Arrays, Booleans ➔ true/false).

📐 FLOWCHART 5: JSON SERIALIZATION & DESERIALIZATION IN PYTHON json.dump() vs json.load()
Python Dictionary in RAM
{"user": "Admin", "id": 101}
➔ json.dump() ➔
JSON File on Hard Disk
Saved as permanent UTF-8 plain text: config.json
▲ json.load() Reads File Back Into Python Dict ▲
Operation File Method (Disk) String Method (In-Memory) Conversion Direction
Serialization (Encoding) json.dump(obj, file) json.dumps(obj) Python Dict / List ➔ JSON format
Deserialization (Decoding) json.load(file) json.loads(string) JSON format ➔ Python Dict / List
🐍 06_json_handling.py
import json

# Python Dictionary with nested structure
college_profile = {
    "institution": "DevAscent Academy",
    "established": 2024,
    "active": True,
    "courses": ["Python for Systems", "Data Structures", "Web Dev"],
    "contact": {
        "email": "support@devascentacademy.me",
        "city": "New Delhi"
    }
}

# 1. Serialization: Saving Python dict to 'profile.json' with indent=4
with open("profile.json", "w", encoding="utf-8") as f:
    json.dump(college_profile, f, indent=4)
print("JSON file saved successfully!")

# 2. Deserialization: Reading JSON file back into Python dictionary
with open("profile.json", "r", encoding="utf-8") as f:
    loaded_data = json.load(f)

print("\nDeserialized Python Data Type:", type(loaded_data).__name__)
print(f"Institution : {loaded_data['institution']}")
print(f"City        : {loaded_data['contact']['city']}")
print(f"Courses (3) : {', '.join(loaded_data['courses'])}")
Terminal Output
JSON file saved successfully! Deserialized Python Data Type: dict Institution : DevAscent Academy City : New Delhi Courses (3) : Python for Systems, Data Structures, Web Dev
8

Unit 10 Practical Capstone: Student File Management Engine

This capstone combines all elements from Unit 10: appending operational logs to a text file with mode="a", saving structured student rosters to CSV, and loading system settings from JSON.

🐍 student_records_manager.py
import csv
import json
import datetime

def log_system_event(action_message):
    """Appends a timestamped audit log to a text file."""
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open("audit_log.txt", "a", encoding="utf-8") as log_file:
        log_file.write(f"[{timestamp}] {action_message}\n")

def save_roster_csv(filename, students):
    """Exports student records to CSV format."""
    fieldnames = ["id", "name", "course", "gpa"]
    with open(filename, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(students)
    log_system_event(f"Exported {len(students)} student records to {filename}")

# Execute Workflow
student_roster = [
    {"id": 101, "name": "Ananya Roy", "course": "BCA 1st Year", "gpa": 8.9},
    {"id": 102, "name": "Siddharth Rao", "course": "B.Tech CSE", "gpa": 9.2},
    {"id": 103, "name": "Kavita Sen", "course": "BCA 1st Year", "gpa": 7.8}
]

save_roster_csv("roster_2026.csv", student_roster)

print("=== AUDIT LOG CONTENTS ===")
with open("audit_log.txt", "r", encoding="utf-8") as f:
    print(f.read().strip())

print("\n=== GENERATED CSV PREVIEW ===")
with open("roster_2026.csv", "r", encoding="utf-8") as f:
    print(f.read().strip())
Terminal Output
=== AUDIT LOG CONTENTS === [2026-10-15 15:48:22] Exported 3 student records to roster_2026.csv === GENERATED CSV PREVIEW === id,name,course,gpa 101,Ananya Roy,BCA 1st Year,8.9 102,Siddharth Rao,B.Tech CSE,9.2 103,Kavita Sen,BCA 1st Year,7.8
9

University Exam & Viva Preparation Guide (Frequently Asked Questions)

Q1. Differentiate between file access modes 'w' and 'a'.
Mode 'w' (Write): Overwrites existing files by truncating their content to zero bytes before writing. If the file exists, previous data is completely erased.
Mode 'a' (Append): Preserves existing file content and positions the file pointer at the end of the file. New data is appended without destroying previous records.
Q2. Why is the `with open()` statement preferred over manual `open()` and `close()`?
The with open() statement employs a Context Manager that guarantees the file is automatically closed as soon as the block terminates, even if an unexpected exception or crash occurs. Manual closing can easily be skipped if an error occurs midway, leading to memory leaks and file lock errors.
Q3. What is the difference between `read()`, `readline()`, and `readlines()`?
• read([n]): Reads the entire file (or up to $n$ bytes) into a single string.
• readline(): Reads a single line (up to newline \n) as a string.
• readlines(): Reads all remaining lines into a list of strings.
Q4. What is the purpose of mode 'x' in Python file handling?
Mode 'x' stands for Exclusive Creation. It creates and opens a new file for writing, but if the file already exists on the disk, it immediately raises a FileExistsError to prevent accidental file corruption or overwrite.
Q5. Differentiate between `json.dump()` and `json.dumps()`.
• json.dump(obj, file_handle): Serializes a Python object directly to an open file on disk.
• json.dumps(obj): Serializes a Python object into an in-memory JSON formatted string.
Q6. Why should you always specify `encoding="utf-8"` when opening text files?
Different operating systems use different default encodings (Windows historically uses cp1252, while Linux uses utf-8). Specifying encoding="utf-8" ensures your Python programs can read and write international characters, emojis, and symbols consistently across all operating systems without throwing UnicodeDecodeError.