File Handling & Modules

Python File Handling

Learn how to read, write, and manage files in Python including text files, CSV, JSON, and best practices with context managers.

Python File Handling

Python provides built-in functions for reading, writing, and manipulating files. Understanding file handling is essential for working with data, configurations, logs, and more.


Opening and Closing Files

python
# Basic file operations
file = open("example.txt", "r")  # Open for reading
content = file.read()
file.close()  # Always close!

# Better: use context manager (auto-closes)
with open("example.txt", "r") as file:
    content = file.read()
# File is automatically closed here

Always use with statements for file handling. They guarantee the file is closed even if an error occurs.


File Modes

ModeDescriptionCreates FileOverwrites
"r"Read (default)NoNo
"w"WriteYesYes
"a"AppendYesNo
"x"Create (fails if exists)YesNo
"r+"Read and writeNoNo
"w+"Write and readYesYes
"b"Binary mode (add to above)
python
# Write mode (creates or overwrites)
with open("output.txt", "w") as f:
    f.write("Hello, World!\n")

# Append mode (adds to end)
with open("output.txt", "a") as f:
    f.write("Another line\n")

# Read mode
with open("output.txt", "r") as f:
    print(f.read())
# Hello, World!
# Another line

Reading Files

Read Entire File

python
with open("data.txt", "r") as f:
    content = f.read()
    print(content)

Read Line by Line

python
# readline() - one line at a time
with open("data.txt", "r") as f:
    line1 = f.readline()  # First line
    line2 = f.readline()  # Second line

# readlines() - all lines as list
with open("data.txt", "r") as f:
    lines = f.readlines()
    for line in lines:
        print(line.strip())

# Iterate directly (most memory-efficient)
with open("data.txt", "r") as f:
    for line in f:
        print(line.strip())

Read with Encoding

python
# Specify encoding (important for non-ASCII text)
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()

Writing Files

python
# Write a string
with open("output.txt", "w") as f:
    f.write("Line 1\n")
    f.write("Line 2\n")

# Write multiple lines
lines = ["Python\n", "is\n", "awesome\n"]
with open("output.txt", "w") as f:
    f.writelines(lines)

# Write with print
with open("output.txt", "w") as f:
    print("Hello, World!", file=f)
    print("Python is great!", file=f)

# Formatted writing
students = [("Alice", 90), ("Bob", 85), ("Charlie", 92)]
with open("grades.txt", "w") as f:
    f.write("Name        Grade\n")
    f.write("-" * 20 + "\n")
    for name, grade in students:
        f.write(f"{name:<12}{grade}\n")

Working with CSV Files

python
import csv

# Writing CSV
students = [
    ["Name", "Age", "Grade"],
    ["Alice", 25, "A"],
    ["Bob", 22, "B"],
    ["Charlie", 28, "A"],
]

with open("students.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(students)

# Reading CSV
with open("students.csv", "r") as f:
    reader = csv.reader(f)
    header = next(reader)  # Skip header
    for row in reader:
        print(f"{row[0]}: Age {row[1]}, Grade {row[2]}")

# Using DictReader/DictWriter
with open("students.csv", "r") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(f"{row['Name']} got {row['Grade']}")

Working with JSON Files

python
import json

# Write JSON
data = {
    "name": "Alice",
    "age": 30,
    "skills": ["Python", "SQL", "ML"],
    "address": {
        "city": "New York",
        "state": "NY"
    }
}

with open("data.json", "w") as f:
    json.dump(data, f, indent=2)

# Read JSON
with open("data.json", "r") as f:
    loaded = json.load(f)
    print(loaded["name"])       # Alice
    print(loaded["skills"][0])  # Python

# JSON string conversion
json_string = json.dumps(data, indent=2)
print(json_string)

data_back = json.loads(json_string)

File System Operations

python
import os
import shutil
from pathlib import Path

# Check file existence
print(os.path.exists("data.txt"))    # True/False
print(os.path.isfile("data.txt"))    # True if file
print(os.path.isdir("data"))         # True if directory

# File information
print(os.path.getsize("data.txt"))   # Size in bytes
print(os.path.basename("/path/to/file.txt"))  # file.txt
print(os.path.dirname("/path/to/file.txt"))   # /path/to

# Create directories
os.makedirs("path/to/dir", exist_ok=True)

# Rename/move
os.rename("old.txt", "new.txt")

# Delete
os.remove("file.txt")          # Delete file
os.rmdir("empty_dir")          # Delete empty directory
shutil.rmtree("dir_with_files") # Delete directory and contents

# List directory contents
for item in os.listdir("."):
    print(item)

# Using pathlib (modern approach)
p = Path("data")
p.mkdir(parents=True, exist_ok=True)

for file in Path(".").glob("*.txt"):
    print(f"{file.name}: {file.stat().st_size} bytes")

The pathlib Module (Modern File Handling)

python
from pathlib import Path

# Create paths
home = Path.home()
project = Path("project")
config = project / "config" / "settings.json"

print(config)           # project/config/settings.json
print(config.parent)    # project/config
print(config.name)      # settings.json
print(config.stem)      # settings
print(config.suffix)    # .json

# Read and write with pathlib
p = Path("example.txt")
p.write_text("Hello, World!")
content = p.read_text()
print(content)  # Hello, World!

# Binary read/write
p.write_bytes(b"binary data")
data = p.read_bytes()

# Check existence
if p.exists():
    print(f"Size: {p.stat().st_size} bytes")

# Iterate directory
for item in Path(".").iterdir():
    if item.is_file():
        print(f"File: {item.name}")
    elif item.is_dir():
        print(f"Dir:  {item.name}/")

# Glob patterns
for py_file in Path(".").rglob("*.py"):
    print(py_file)

Exception Handling with Files

python
# Handle file errors gracefully
try:
    with open("missing_file.txt", "r") as f:
        content = f.read()
except FileNotFoundError:
    print("File not found!")
except PermissionError:
    print("Permission denied!")
except IOError as e:
    print(f"IO error: {e}")

Practical Example: Log File Analyzer

python
"""
Analyze a log file and generate a summary.
"""

from pathlib import Path
from collections import Counter
from datetime import datetime

def analyze_log(log_path):
    """Analyze a log file and return statistics."""
    levels = Counter()
    errors = []
    line_count = 0

    path = Path(log_path)
    if not path.exists():
        print(f"Log file not found: {log_path}")
        return

    with open(path, "r", encoding="utf-8") as f:
        for line in f:
            line_count += 1
            line = line.strip()

            # Count log levels
            for level in ["ERROR", "WARNING", "INFO", "DEBUG"]:
                if level in line:
                    levels[level] += 1
                    if level == "ERROR":
                        errors.append(line)
                    break

    # Generate report
    report = f"""
Log Analysis Report
{'=' * 40}
File: {log_path}
Total lines: {line_count}
Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}

Log Level Summary:
"""
    for level, count in levels.most_common():
        bar = "█" * (count * 2)
        report += f"  {level:<10} {count:>5}  {bar}\n"

    if errors:
        report += f"\nErrors ({len(errors)}):\n"
        for error in errors[:5]:
            report += f"  • {error[:80]}\n"

    return report

Summary

  • Always use with statements (context managers) for file handling
  • File modes: "r" (read), "w" (write), "a" (append), "x" (create)
  • Reading: read(), readline(), readlines(), or iterate directly
  • Writing: write(), writelines(), or print(file=f)
  • Use csv module for CSV files and json module for JSON files
  • pathlib.Path is the modern, Pythonic way to handle file paths
  • Always handle FileNotFoundError and other IO exceptions
  • Specify encoding (utf-8) when working with text files

Next, we'll learn about Python modules and packages.