File I/O is essential for reading config, processing data, and saving results. Python provides built-in tools for text, structured, and binary files.

Reading and Writing Text Files

  # Write
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("Line 1\n")
    f.write("Line 2\n")

# Read entire file
with open("output.txt", "r", encoding="utf-8") as f:
    content = f.read()

# Read line by line (memory-efficient for large files)
with open("output.txt", "r") as f:
    for line in f:
        print(line.strip())

# Read all lines into a list
with open("output.txt") as f:
    lines = f.readlines()
  

Always use with open(...) — files close automatically, even on errors.

File Modes

Mode Description
r Read (default)
w Write (overwrites)
a Append
x Create (fails if exists)
r+ Read and write
rb, wb Binary read/write

pathlib — Modern Path Handling

  from pathlib import Path

data_dir = Path("data")
data_dir.mkdir(exist_ok=True)

file_path = data_dir / "report.txt"
file_path.write_text("Hello, pathlib!", encoding="utf-8")
content = file_path.read_text(encoding="utf-8")

for csv_file in data_dir.glob("*.csv"):
    print(csv_file.name)

print(file_path.exists())
print(file_path.stat().st_size)
print(file_path.parent)
print(file_path.suffix)
  

Prefer pathlib over os.path for new code.

CSV Files

  import csv

# Reading
with open("employees.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], row["salary"])

# Writing
employees = [
    {"name": "Alice", "department": "Engineering", "salary": 90000},
    {"name": "Bob", "department": "Sales", "salary": 75000},
]

with open("output.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "department", "salary"])
    writer.writeheader()
    writer.writerows(employees)
  

JSON Files

  import json

data = {
    "name": "Alice",
    "age": 30,
    "skills": ["Python", "SQL"],
    "active": True,
}

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

# Read
with open("user.json") as f:
    loaded = json.load(f)

# String serialization
json_str = json.dumps(data)
parsed = json.loads(json_str)
  

JSON only supports: objects, arrays, strings, numbers, booleans, and null.

Binary Files

  # Copy a binary file
with open("photo.jpg", "rb") as src, open("copy.jpg", "wb") as dst:
    dst.write(src.read())

# Read bytes in chunks
with open("large_file.bin", "rb") as f:
    while chunk := f.read(8192):
        process(chunk)
  

Working with Directories

  from pathlib import Path
import shutil

src = Path("old_folder")
dst = Path("new_folder")

dst.mkdir(parents=True, exist_ok=True)
shutil.copy("file.txt", dst / "file.txt")
shutil.move(str(src / "archive"), dst / "archive")
shutil.rmtree("temp_dir")  # delete directory tree
  

Temporary Files

  import tempfile
import os

with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".txt") as f:
    f.write("temporary data")
    temp_path = f.name

# use temp_path...
os.remove(temp_path)
  

Error Handling

  from pathlib import Path

def safe_read(path):
    file = Path(path)
    if not file.exists():
        raise FileNotFoundError(f"No such file: {path}")
    if file.stat().st_size > 10_000_000:
        raise ValueError("File too large (>10MB)")
    return file.read_text(encoding="utf-8")
  

Best Practices

  1. Always specify encodingencoding="utf-8" for text files
  2. Use context managerswith open(...) or Path.read_text()
  3. Stream large files — read line-by-line or in chunks
  4. Use pathlib — cleaner than string path concatenation
  5. Validate before processing — check existence, size, format

File handling connects your Python programs to the real world of data on disk.