Logo OnlineCBT
PYTHON Tutorial
PYTHON · LESSON 27

Files, Paths and Text I/O

Read and write text safely with pathlib and explicit encodings.

Level: Beginner to Advanced
Duration: ~60 Mins Deep-Dive
Updated: 26 Jul 2026

Lesson 27: Files, Paths and Text I/O

1. Introduction to Data Persistence and File Systems

Welcome to Module 3 of our Python Mastery Series: Persistent Data, File Systems and Input/Output! Up to this point, all data structures, variables, lists, dictionaries, and state objects we constructed resided exclusively in volatile System RAM (Random Access Memory). The moment a script finishes execution or the terminal closes, volatile memory is wiped clean, and all computed results vanish permanently.

Production applications require Data Persistence—storing state permanently on non-volatile secondary storage (Solid State Drives or Hard Disk Drives). Whether writing application log files, saving customer records, storing configuration settings, or loading analytical reports, reading and writing files is a fundamental software engineering requirement.

In this lesson, we will master Python's built-in file handling mechanisms using `open()`, safe resource cleanup via Context Managers (`with` blocks), cross-platform path management using the modern `pathlib` module, character encodings (`utf-8`), and routing file-system operations cleanly with Structural Pattern Matching (`match-case`).


2. Modern Cross-Platform Path Manipulation with `pathlib`

Historically, developers manipulated file paths as raw text strings or used legacy os.path string-joining functions. However, hardcoding path strings creates severe cross-platform bugs because Windows uses backslashes (C:\Users\Main) while Linux and macOS use forward slashes (/home/user/main).

Python 3.4+ solved this permanently by introducing the standard `pathlib` module. The Path object provides an object-oriented, cross-platform interface that automatically uses the correct path separators for the host Operating System.

1. Core `pathlib.Path` Operations

  • Current Working Directory
  • Path.cwd()
  • Returns absolute path of directory where Python process was launched.
  • Path Join Operator
  • base_dir / "logs" / "app.log"
  • Uses slash operator (/) to concatenate path segments safely.
  • Exists Check
  • path_obj.exists()
  • Returns True if target file or folder exists on disk.
  • Is File / Is Directory?
  • path_obj.is_file() / path_obj.is_dir()
  • Evaluates whether target path is a file or a folder.
  • Directory Creation
  • path_obj.mkdir(parents=True, exist_ok=True)
  • Creates directory tree safely without crashing if folder already exists.
  • Path Metadata Attributes
  • path.name, path.stem, path.suffix
  • Extracts filename, base name without extension, or file extension (e.g., .txt).
Path Inspection Method Code Syntax Example Behavior Description
PATHLIB_BASICS_DEMO.PY
from pathlib import Path

# Instantiating base working directory
working_dir = Path.cwd()
data_folder = working_dir / "system_storage"

# Safely creating folder hierarchy on disk
data_folder.mkdir(parents=True, exist_ok=True)

# Creating target file path object
log_file_path = data_folder / "audit_event.log"

print("=== Cross-Platform Path Inspection ===")
print("Absolute Folder Path :", data_folder)
print("Target File Path     :", log_file_path)
print("File Base Name (stem):", log_file_path.stem)
print("File Extension       :", log_file_path.suffix)
print("Does Folder Exist?   :", data_folder.exists())
OUTPUT
=== Cross-Platform Path Inspection ===
Absolute Folder Path : /workspace/python_mastery_course/system_storage
Target File Path     : /workspace/python_mastery_course/system_storage/audit_event.log
File Base Name (stem): audit_event
File Extension       : .log
Does Folder Exist?   : True

3. The `open()` Function and File Access Modes

To interact with files on disk, Python provides the built-in open(file, mode='r', encoding='utf-8') function. It establishes a stream buffer connection between Python and the underlying Operating System file system.

1. Comprehensive File Opening Modes Matrix

  • 'r'
  • Read (Default)
  • Pointer placed at **start of file** for reading.
  • Raises FileNotFoundError
  • 'w'
  • Write (Overwrite)
  • Truncates existing content to 0 bytes! Overwrites completely.
  • Creates new empty file
  • 'a'
  • Append
  • Pointer placed at **end of file**. Preserves prior content.
  • Creates new empty file
  • 'x'
  • Exclusive Creation
  • Opens stream strictly for creation and writing.
  • Raises FileExistsError if file exists
  • 'r+' / 'w+'
  • Read + Write
  • Opens bidirectional stream for simultaneous reading and writing.
  • Depends on r or w rule
Mode Keyword Mode Full Name File Stream Pointer Behavior File Non-Existence Action
The Encoding Requirement (`encoding="utf-8"`): ALWAYS specify encoding="utf-8" explicitly when calling open()! If omitted, Python defaults to the host Operating System's local locale encoding (e.g., cp1252 on Windows), leading to character corruption or UnicodeDecodeError exceptions when reading special characters, emojis, or international text!

4. Safe Resource Management: Context Managers (`with` Blocks)

When you open a file stream, the Operating System allocates system resources (file descriptors). If a program opens hundreds of files without closing them, system memory leaks occur, file locks persist, and data written to buffers might not flush to physical disk storage.

1. Why Un-Managed `open()` is Dangerous

# DANGEROUS / UNPYTHONIC ANTI-PATTERN:
file_handle = open("data.txt", "w")
file_handle.write("Sample content")
# If an exception occurs right here, file_handle.close() NEVER RUNS!
file_handle.close()
    

2. The Pythonic Solution: The `with` Statement

A Context Manager (introduced by the with keyword) guarantees that Python automatically closes the file stream when execution exits the indented block—even if runtime exceptions or unexpected errors occur inside the block!

CONTEXT_MANAGER_DEMO.PY
from pathlib import Path

target_path = Path.cwd() / "sample_output.txt"

# 1. Writing Text using Context Manager ('w' mode)
with open(target_path, mode="w", encoding="utf-8") as file:
    file.write("Header: System Configuration File\n")
    file.write("Version: 1.0.0\n")
    file.write("Status: Operational\n")

# File is automatically closed here!

# 2. Appending Text using Context Manager ('a' mode)
with open(target_path, mode="a", encoding="utf-8") as file:
    file.write("Log Entry: Maintenance completed successfully.\n")

print(f"File successfully written to: {target_path.name}")
print(f"File Stream Closed? : {file.closed}")  # Proves automatic cleanup!
OUTPUT
File successfully written to: sample_output.txt
File Stream Closed? : True

5. Reading Strategies: `.read()`, `.readline()`, and Iteration

Python provides multiple methods to consume text content from an open file stream, each tailored to different file sizes:

1. Reading Full Content (`.read()`)

Reads the entire file into a single string. Useful for small text files, but dangerous for huge multi-gigabyte log files as it loads everything into RAM at once.

2. Line-by-Line List Extraction (`.readlines()`)

Reads all lines and returns a list of string lines (retaining trailing \n newline characters).

3. High-Performance Stream Iteration (`for line in file:`)

The standard Pythonic way to read large files! It streams one line at a time into memory lazily with minimal RAM consumption.

READING_STRATEGIES_DEMO.PY
from pathlib import Path

target_path = Path.cwd() / "sample_output.txt"

print("--- Strategy 1: Iterating Line-by-Line (Memory Efficient) ---")
with open(target_path, mode="r", encoding="utf-8") as file:
    for line_no, line_content in enumerate(file, start=1):
        # Stripping trailing newline for clean console printing
        clean_line = line_content.rstrip("\n")
        print(f"Line #{line_no:02d} | {clean_line}")

print("\n--- Strategy 2: Extracting Lines into a List ---")
with open(target_path, mode="r", encoding="utf-8") as file:
    lines_list = [line.strip() for line in file if "Log Entry" in line]

print("Filtered Matching Lines:", lines_list)
OUTPUT
--- Strategy 1: Iterating Line-by-Line (Memory Efficient) ---
Line #01 | Header: System Configuration File
Line #02 | Version: 1.0.0
Line #03 | Status: Operational
Line #04 | Log Entry: Maintenance completed successfully.

--- Strategy 2: Extracting Lines into a List ---
Filtered Matching Lines: ['Log Entry: Maintenance completed successfully.']

6. Robust File I/O Exception Handling

File system operations are prone to runtime environment errors (e.g., missing files, insufficient disk permissions, full disks, or corrupted encodings). Wrap file operations in try-except blocks to handle errors gracefully.

FILE_IO_EXCEPTIONS.PY
from pathlib import Path

non_existent_file = Path.cwd() / "missing_config.json"

try:
    with open(non_existent_file, mode="r", encoding="utf-8") as f:
        content = f.read()
except FileNotFoundError as err:
    print(f"IO_ERROR: Target file does not exist! details: {err.filename}")
except PermissionError:
    print("SECURITY_ERROR: Access denied due to file permissions!")
except Exception as gen_err:
    print(f"UNKNOWN_ERROR: Unexpected error occurred -> {gen_err}")
OUTPUT
IO_ERROR: Target file does not exist! details: missing_config.json

7. Integrating File Operations with `match-case` Pattern Matching

Combining pathlib.Path operations and context managers with match-case structural pattern matching creates clean, robust CLI file-management utilities.

MATCH_CASE_FILE_DISPATCHER.PY
from pathlib import Path

def execute_file_command(command_payload: list):
    """
    Executes file system actions using Structural Pattern Matching.
    Demonstrates handling file paths and text I/O dynamically.
    """
    match command_payload:
        case ["WRITE", filename, *lines] if len(lines) > 0:
            file_path = Path.cwd() / filename
            with open(file_path, mode="w", encoding="utf-8") as f:
                for line in lines:
                    f.write(f"{line}\n")
            return f"SUCCESS: Wrote {len(lines)} lines to '{filename}'."
            
        case ["READ", filename]:
            file_path = Path.cwd() / filename
            if not file_path.exists():
                return f"ERROR: File '{filename}' not found!"
            with open(file_path, mode="r", encoding="utf-8") as f:
                content = f.read().strip()
            return f"=== CONTENTS OF '{filename}' ===\n{content}"
            
        case ["APPEND", filename, new_content]:
            file_path = Path.cwd() / filename
            with open(file_path, mode="a", encoding="utf-8") as f:
                f.write(f"{new_content}\n")
            return f"SUCCESS: Appended entry to '{filename}'."
            
        case ["DELETE", filename]:
            file_path = Path.cwd() / filename
            if file_path.exists():
                file_path.unlink()  # Deletes file from disk
                return f"SUCCESS: Deleted file '{filename}' from disk."
            return f"WARNING: Cannot delete missing file '{filename}'."
            
        case _:
            return "ERROR: Unrecognized file system command."

# Testing the file dispatcher
print(execute_file_command(["WRITE", "test_log.txt", "Line A: System Init", "Line B: Server Active"]))
print(execute_file_command(["APPEND", "test_log.txt", "Line C: Shutdown Request"]))
print(execute_file_command(["READ", "test_log.txt"]))
print(execute_file_command(["DELETE", "test_log.txt"]))
OUTPUT
SUCCESS: Wrote 2 lines to 'test_log.txt'.
SUCCESS: Appended entry to 'test_log.txt'.
=== CONTENTS OF 'test_log.txt' ===
Line A: System Init
Line B: Server Active
Line C: Shutdown Request
SUCCESS: Deleted file 'test_log.txt' from disk.

8. Frequently Asked Interview Questions with Answers

Q1: What is a Context Manager in Python, and why is the `with` statement used for file I/O?
Answer: A Context Manager sets up a temporary runtime context using __enter__() and __exit__() methods. Using with open(...) as f: guarantees that the file stream is closed automatically upon exiting the block, preventing resource leaks, file locks, and un-flushed buffers even if uncaught runtime exceptions occur inside the block.
Q2: Why is `pathlib.Path` preferred over legacy string manipulation for file paths?
Answer: pathlib.Path provides a cross-platform, object-oriented interface that handles path separator differences (Windows backslashes vs. Posix forward slashes) transparently. It eliminates string-formatting path errors and offers clean built-in methods like .exists(), .mkdir(), and .unlink().
Q3: What is the difference between file access modes `'w'` and `'a'`?
Answer: Mode 'w' (Write) truncates the existing file content to 0 bytes, overwriting the file completely. Mode 'a' (Append) positions the file pointer at the end of the file, preserving existing content and appending new data to the bottom. Both modes create a new file if it does not already exist.
Q4: Why should you explicitly specify `encoding="utf-8"` when opening text files?
Answer: If omitted, Python falls back to the host operating system's default local encoding (e.g., cp1252 on Windows or utf-8 on Linux). Explicitly setting encoding="utf-8" guarantees consistent, portable text rendering and prevents UnicodeDecodeError exceptions across different OS environments.
Q5: What is the memory advantage of streaming a file line-by-line using a `for` loop over `.read()`?
Answer: Calling .read() loads the entire file content into RAM simultaneously, which can crash execution when processing massive multi-gigabyte files. Streaming via for line in file: uses lazy iteration, holding only one line in memory at any given moment, resulting in constant $O(1)$ RAM usage.

9. Homework & Practical Assignments

Task 1: Log File Writer and Line Stream Inspector

Create a script named log_stream_task.py inside your lesson_27 folder:

  • Import Path from pathlib.
  • Create a directory logs_dir using .mkdir(parents=True, exist_ok=True).
  • Use a with open() block in mode 'w' to write 5 lines of system diagnostic messages to app_events.log with encoding='utf-8'.
  • Re-open the log file in mode 'r', iterate using a for loop with enumerate(), and display line numbers alongside uppercase line text.

Task 2: File System Command Router with `match-case`

Create a script named file_command_task.py:

  • Define a function manage_text_file(command_tokens: list).
  • Use match-case pattern matching:
    • case ["CREATE", filename, *contents] → Write content lines to disk using a context manager.
    • case ["CHECK", filename] → Check if file exists using Path(filename).exists() and display file size using .stat().st_size.
    • case ["PURGE", filename] → Delete file safely using .unlink(missing_ok=True).
    • case _ → Output error message string.
  • Test function with sample command inputs and print results using f-strings.

Task 3: Master Review Capstone Project — Enterprise Persistent Audit OS (`audit_logger_os.py`)

Create a script named audit_logger_os.py inside your lesson_27 folder. This assignment tests and integrates **ALL concepts learned across Lessons 1 through 27**.

Project Architectural Requirements Specification:

  1. Environment, Modules & Entry Guard (Lessons 18-20):
    • Import standard library modules (sys, datetime, json) and Path from pathlib.
    • Wrap main application execution inside an if __name__ == "__main__": guard block.
  2. File I/O & Path Persistence (Lesson 27):
    • Maintain a persistent storage directory audit_vault/ using pathlib.Path.
    • Write all event transactions to persistent disk files (system_audit.log) using with open(..., mode="a", encoding="utf-8").
    • Implement safe file reading and stream search helpers with try-except error guards.
  3. Nested Collections & Data Modelling (Lesson 26):
    • Maintain an in-memory active session cache represented as nested dictionaries and lists of tuples.
    • Perform multi-key sorting on log memory records using operator.itemgetter or custom lambda key tuples.
  4. Comprehensions & Core Data Structures (Lessons 21-25):
    • Use List and Set Comprehensions to clean, filter, and extract unique log tags directly from log file lines.
    • Use set algebra (Union, Intersection, Difference) to evaluate access permission overlaps.
  5. Advanced Function Parameters & Scope (Lessons 15-17):
    • Structure code into pure modular functions with type hints, docstrings, early return Guard Clauses, and *args / **kwargs logging.
  6. Indefinite & Definite Loops (Lessons 13-14):
    • Run the main application inside a continuous while True interactive CLI menu loop.
    • Iterate through record streams using for loops with enumerate().
  7. Pattern Matching CLI Dispatcher (Lesson 12):
    • Process user CLI command tokens inside a match-case block:
      • case ["LOG", level, service, *message_tokens] → Write formatted record to log file and memory cache.
      • case ["READ", "LOGS"] → Stream and display log file contents from disk.
      • case ["SEARCH", keyword] → Use list comprehensions to search log file lines.
      • case ["CLEAR", "VAULT"] → Purge log files from disk safely.
      • case ["EXIT" | "QUIT"] → Terminate session safely using a sentinel flag.
      • case _ → Output command error message.
  8. Conditionals, Formatting & Foundations (Lessons 1-11):
    • Sanitize all inputs using .strip() and .upper().
    • Format tabular reports using f-strings with field width alignment specifiers (:<15, :>10) and clear visual borders.

10. File & Workspace Directory Structure

Standard Course Workspace Layout:

Ensure all exercise files are stored inside their corresponding lesson directories:

python_mastery_course/
│
├── lesson_01/ ... lesson_26/
│
└── lesson_27/
    ├── pathlib_basics_demo.py
    ├── context_manager_demo.py
    ├── reading_strategies_demo.py
    ├── file_io_exceptions.py
    ├── match_case_file_dispatcher.py
    ├── log_stream_task.py          <-- (Task 1)
    ├── file_command_task.py        <-- (Task 2)
    └── audit_logger_os.py          <-- (Task 3: Master Review Capstone)
        

11. What We Will Learn Next

Next Up: Lesson 28 — CSV and JSON Data

Now that you master basic text file I/O and cross-platform path management, we will explore working with industry-standard structured data formats!

In the next lesson, we will cover:

  • Reading and Writing Comma-Separated Values using the standard `csv` module (csv.reader, csv.writer, csv.DictReader).
  • Parsing and Serializing JSON web API data using the standard `json` module (json.dumps(), json.loads(), json.dump(), json.load()).
  • Mapping JSON objects to Python Dictionaries and Lists seamlessly.
  • Handling date serialization and formatting exceptions in JSON streams.
  • Building structured file-backed databases for CLI applications.

📝 Live Lesson Practice

HTML/CSS JavaScript Python C++ C PHP
⌨️ Practice Inputs (लाइव इनपुट भरें) (खाली होने पर RED, भरने पर GREEN underline)
💻 Code Editor (Monaco VS Code Engine)
👀 Live Preview
Address Contact

+91 7877547686

E-mail

onlinecbtportal@gmail.com

Helpline Number

+91 7877547686


Click To Download
Get it on Google Play

ऐप डाउनलोड करने
के लिए Google Play पर
उपलब्ध है

WhatsApp Chat