File Handling
open() and the with statement. All file modes (r, w, a, r+). Reading methods: read(), readline(), readlines(). CSV files with the csv module. JSON files with json. Working with file paths using pathlib.
Opening Files — The with Statement
Python uses open(filename, mode) to open a file. Always use the with statement (context manager) — it guarantees the file is properly closed even if an error occurs. Without with, you risk file corruption and resource leaks.
| Mode | Name | Behaviour |
|---|---|---|
| "r" | Read | Open for reading. File must exist or FileNotFoundError. |
| "w" | Write | Create new (or truncate existing). Destroys existing content! |
| "a" | Append | Open for writing at end. Creates file if it doesn't exist. |
| "r+" | Read+Write | Open for both reading and writing. File must exist. |
| "x" | Exclusive Create | Create new file. Fails if it already exists. |
| "b" | Binary suffix | Add to any mode: "rb", "wb" — for images, PDFs, etc. |
# ── WRITING a file ─────────────────────────── with open("notes.txt", "w", encoding="utf-8") as f: f.write("Line 1: Python is awesome!\n") f.write("Line 2: File handling is easy.\n") f.write("Line 3: Always use 'with'.\n") # File is automatically closed here # ── READING the whole file at once ─────────── with open("notes.txt", "r", encoding="utf-8") as f: content = f.read() print(content) # ── READING line by line (memory-efficient) ── with open("notes.txt", "r", encoding="utf-8") as f: for line in f: print(line.strip()) # strip removes the trailing \n # ── READING into a list ─────────────────────── with open("notes.txt") as f: lines = f.readlines() # list of strings, each with \n print(f"{len(lines)} lines read") # ── APPENDING to existing file ─────────────── with open("notes.txt", "a", encoding="utf-8") as f: f.write("Line 4: Appended without overwriting!\n") # ── WRITING multiple lines at once ─────────── data = ["Ali\n", "Sara\n", "Zara\n"] with open("names.txt", "w") as f: f.writelines(data)
encoding="utf-8"encoding="utf-8" explicitly. It's also required for deployment on servers.CSV Files
CSV (Comma-Separated Values) is the most common format for tabular data — spreadsheets, database exports, data science datasets. Python's built-in csv module handles all the edge cases (quoted fields, commas inside values, different delimiters) that manual string splitting misses.
import csv # ── WRITING a CSV ───────────────────────────── students = [ ["Name", "Age", "GPA", "City"], # header row ["Ali", 20, 3.85, "Lahore"], ["Sara", 22, 3.92, "Karachi"], ["Fatima", 21, 3.75, "Islamabad"], ] with open("students.csv", "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerows(students) # ── READING a CSV ───────────────────────────── with open("students.csv", "r", encoding="utf-8") as f: reader = csv.reader(f) for row in reader: print(row) # ── DictReader — rows as dicts (headers as keys) ─ with open("students.csv", "r", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: print(f"{row['Name']}: GPA {row['GPA']}") # Ali: GPA 3.85 # Sara: GPA 3.92 # ── DictWriter — write dicts to CSV ────────── records = [ {"product": "Book", "price": 1500}, {"product": "Keyboard", "price": 3200}, ] with open("products.csv", "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=["product", "price"]) writer.writeheader() writer.writerows(records)
newline="" when writing CSV on Windows\r carriage return character to each line. The csv module adds its own line endings, so you get double-newlines. Fix: always pass newline="" to open() when using the csv module.JSON Files
JSON (JavaScript Object Notation) is the universal format for web APIs, configuration files, and data exchange. Python's json module converts between Python dicts/lists and JSON text with two key functions: json.dumps() (to string) and json.dump() (to file). json.loads() (from string) and json.load() (from file) go the other way.
import json data = { "app" : "BitWithBite", "version": "2.0", "students": [ {"name": "Ali", "gpa": 3.85}, {"name": "Sara", "gpa": 3.92}, ], "active": True } # ── Write to JSON file ──────────────────────── with open("data.json", "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) # indent=2 makes it human-readable # ensure_ascii=False preserves Urdu/Arabic characters # ── Read from JSON file ─────────────────────── with open("data.json", "r", encoding="utf-8") as f: loaded = json.load(f) print(loaded["app"]) # BitWithBite print(loaded["students"][0]["name"]) # Ali # ── JSON string conversion ──────────────────── json_str = json.dumps(data, indent=2) # dict → string back = json.loads(json_str) # string → dict # ── Useful pattern: update a JSON config ───── def update_config(path, key, value): with open(path) as f: config = json.load(f) config[key] = value with open(path, "w") as f: json.dump(config, f, indent=2) update_config("data.json", "version", "2.1")
pathlib — Modern Path Handling
Python 3.6+ includes pathlib, the modern object-oriented way to work with file system paths. It's far better than string concatenation for paths — it works identically on Windows, macOS, and Linux, and has a clean, fluent API.
from pathlib import Path # Current directory cwd = Path.cwd() print(cwd) # Build paths with / operator (works on all OS!) data_dir = cwd / "data" file_path= data_dir / "students.csv" # Create directories data_dir.mkdir(exist_ok=True) # no error if already exists # Path properties p = Path("data/students.csv") print(p.name) # students.csv print(p.stem) # students print(p.suffix) # .csv print(p.parent) # data print(p.exists()) # True/False print(p.is_file()) # True if it's a file # Read/write directly from Path objects config = Path("config.txt") config.write_text("debug=True\nport=8000\n", encoding="utf-8") print(config.read_text(encoding="utf-8")) # List all files matching a pattern for csv_file in Path(".").glob("*.csv"): print(f"Found: {csv_file.name} ({csv_file.stat().st_size} bytes)") # Recursive glob — find all Python files in any subdirectory for py_file in Path(".").rglob("*.py"): print(py_file)
os.path.join("data", "file.csv") — error-prone on Windows vs Linux. New code uses Path("data") / "file.csv" — clean, cross-platform, and object-oriented. Pathlib objects can be passed directly to open(), json.load(), and most modern libraries.with statement when opening files?json.dumps(data) return?csv.DictReader return for each row?1. Loads students from a CSV file (
students.csv) using DictReader — columns: name, age, gpa, city2. Converts each row's gpa to float; groups students into
{"honours": [], "pass": [], "fail": []} based on gpa thresholds (≥3.7 honours, ≥2.0 pass, else fail)3. Saves the grouped report to a JSON file (
report.json) with indent=24. Adds a new student via user input and appends them to the CSV file
5. Uses pathlib to check if
students.csv exists before reading, and creates it with sample data if it doesn't6. Prints a summary: total students, honours count, average GPA
💡 Show hints
- Pathlib check:
if not Path("students.csv").exists(): ...then write sample data - Append row: open with "a", use csv.writer, write one row
- Average GPA:
sum(float(r["gpa"]) for r in rows) / len(rows) - grouping: build dict, then .setdefault() or just if/elif
import csv, json from pathlib import Path CSV_FILE = Path("students.csv") JSON_FILE = Path("report.json") # ── Create sample CSV if missing ────────────── if not CSV_FILE.exists(): sample = [ ["name", "age", "gpa", "city"], ["Ali", 20, 3.85, "Lahore"], ["Sara", 22, 3.92, "Karachi"], ["Zara", 21, 2.50, "Multan"], ["Omar", 23, 1.80, "Quetta"], ] with open(CSV_FILE, "w", newline="") as f: csv.writer(f).writerows(sample) print("✅ Created sample students.csv") # ── Load and group ──────────────────────────── with open(CSV_FILE, encoding="utf-8") as f: rows = list(csv.DictReader(f)) groups = {"honours": [], "pass": [], "fail": []} for r in rows: g = float(r["gpa"]) if g >= 3.7: groups["honours"].append(r["name"]) elif g >= 2.0: groups["pass"].append(r["name"]) else: groups["fail"].append(r["name"]) # ── Save JSON report ────────────────────────── with open(JSON_FILE, "w") as f: json.dump(groups, f, indent=2) print(f"✅ Report saved to {JSON_FILE}") # ── Add a new student ───────────────────────── print("\n Add a new student:") new = { "name": input(" Name : ").strip().title(), "age" : input(" Age : ").strip(), "gpa" : input(" GPA : ").strip(), "city": input(" City : ").strip().title(), } with open(CSV_FILE, "a", newline="") as f: csv.DictWriter(f, fieldnames=["name","age","gpa","city"]).writerow(new) print(f" ✅ {new['name']} added!") # ── Summary ─────────────────────────────────── avg_gpa = sum(float(r["gpa"]) for r in rows) / len(rows) print(f"\n Students: {len(rows)} Honours: {len(groups['honours'])} Avg GPA: {avg_gpa:.2f}")