Opening and reading files
open() returns a file object. Always use it as a context manager with with so the file is closed automatically, even if an exception occurs.
1# Read the entire file as one string2with open("notes.txt", "r") as f:3 content = f.read()4 print(content)56# Read line by line, memory-efficient for large files7with open("notes.txt") as f: # "r" is the default mode8 for line in f:9 print(line, end="") # lines already include \n1011# Read all lines into a list12with open("notes.txt") as f:13 lines = f.readlines() # ['line 1\n', 'line 2\n', ...]1415# Read one line at a time16with open("notes.txt") as f:17 first = f.readline() # 'line 1\n'
Encoding
Always specify encoding="utf-8" explicitly. The default depends on the operating system and can vary between machines, causing silent data corruption on non-ASCII characters.
1# Explicit encoding, always do this2with open("data.txt", encoding="utf-8") as f:3 content = f.read()45# Common encodings6# utf-8 universal, handles all Unicode7# utf-8-sig UTF-8 with BOM (common in Windows-generated CSVs)8# latin-1 legacy Western European files
Each mode controls what operations are allowed and how the file is opened.
Writing files
Mode "w" creates the file if it does not exist and overwrites it if it does. Mode "a" appends to the end, preserving existing content. Both create the file if absent.
1# Write, creates or overwrites2with open("output.txt", "w", encoding="utf-8") as f:3 f.write("Hello, world!\n")4 f.write("Second line\n")56# writelines, no automatic newlines added7lines = ["one\n", "two\n", "three\n"]8with open("output.txt", "w", encoding="utf-8") as f:9 f.writelines(lines)1011# Append, adds to end without truncating12with open("log.txt", "a", encoding="utf-8") as f:13 f.write("2024-01-15 server started\n")
Writing structured data
1# Write a table of data cleanly2headers = ["name", "score", "grade"]3rows = [4 ["Alice", "92", "A"],5 ["Bob", "78", "C+"],6 ["Carol", "85", "B"],7]89with open("results.txt", "w", encoding="utf-8") as f:10 f.write("\t".join(headers) + "\n")11 for row in rows:12 f.write("\t".join(row) + "\n")
Binary files
Add "b" to the mode for binary files. The file object reads and writes bytes instead of strings. No encoding conversion happens.
1# Copy a file byte-for-byte2with open("image.png", "rb") as src:3 with open("copy.png", "wb") as dst:4 dst.write(src.read())56# Read in chunks, for large files7with open("large.bin", "rb") as f:8 while chunk := f.read(8192): # walrus operator, Python 3.8+9 process(chunk)
pathlib
pathlib.Path is the modern way to work with file paths. It is object-oriented, cross-platform, and far more readable than string concatenation or os.path. Prefer it for all new code.
1from pathlib import Path23p = Path("/home/user/documents/report.pdf")45# Parts and properties6print(p.name) # report.pdf7print(p.stem) # report8print(p.suffix) # .pdf9print(p.parent) # /home/user/documents1011# Building paths with /12base = Path("/home/user")13config = base / "config" / "settings.json"14print(config) # /home/user/config/settings.json1516# Current directory and relatives17here = Path.cwd()18home = Path.home()19sibling = Path(__file__).parent / "data.csv"
Common operations
1from pathlib import Path23p = Path("data/output.txt")45# Check existence and type6print(p.exists()) # True/False7print(p.is_file()) # True if it's a regular file8print(p.is_dir()) # True if it's a directory910# Create directories11Path("logs/2024").mkdir(parents=True, exist_ok=True)1213# Read and write directly, no open() needed14p.write_text("hello\n", encoding="utf-8")15content = p.read_text(encoding="utf-8")1617p.write_bytes(b"\x00\x01\x02")18data = p.read_bytes()1920# Glob for files21for csv_file in Path("data").glob("*.csv"):22 print(csv_file.name)2324# Recursive glob25for py_file in Path(".").rglob("*.py"):26 print(py_file)
File operations
1from pathlib import Path2import shutil34src = Path("report.txt")5dst = Path("archive/report_backup.txt")67# Rename / move8src.rename(dst) # moves within the same filesystem9shutil.move(str(src), str(dst)) # works across filesystems1011# Copy12shutil.copy2(src, dst) # copy with metadata1314# Delete15src.unlink() # delete file16src.unlink(missing_ok=True) # no error if absent (Python 3.8+)1718Path("empty_dir").rmdir() # delete empty dir19shutil.rmtree("dir_tree") # delete directory and all contents
JSON files
Python's json module serializes Python objects to JSON strings and back. The four functions you need: dump (to file), dumps (to string), load (from file), loads (from string).
1import json23# Write to a file4config = {"host": "localhost", "port": 5432, "debug": False}5with open("config.json", "w", encoding="utf-8") as f:6 json.dump(config, f, indent=2)78# Read from a file9with open("config.json", encoding="utf-8") as f:10 loaded = json.load(f)11print(loaded["port"]) # 54321213# Serialize to/from strings (e.g. for HTTP responses)14json_str = json.dumps(config, indent=2)15print(type(json_str)) # <class 'str'>1617back = json.loads(json_str)18print(type(back)) # <class 'dict'>
Type mapping
1# Python → JSON2# dict → object {}3# list → array []4# tuple → array [] (round-trips as list)5# str → string ""6# int → number7# float → number8# True → true9# False → false10# None → null1112data = {"items": (1, 2, 3), "flag": True, "value": None}13print(json.dumps(data))14# {"items": [1, 2, 3], "flag": true, "value": null}1516# json cannot serialize: sets, datetimes, custom classes17import datetime18# json.dumps(datetime.date.today()) # TypeError1920# Fix: convert manually or use a custom encoder21print(json.dumps(datetime.date.today(), default=str))22# "2024-01-15"
Useful options
1data = {"z": 3, "a": 1, "m": 2}23# sort_keys, deterministic output (good for testing and diffs)4print(json.dumps(data, sort_keys=True))5# {"a": 1, "m": 2, "z": 3}67# indent, human-readable formatting8print(json.dumps(data, indent=2))9# {10# "z": 3,11# "a": 1,12# "m": 213# }1415# ensure_ascii=False, keep Unicode characters as-is16print(json.dumps({"city": "Zürich"}, ensure_ascii=False))17# {"city": "Zürich"}
See how Python objects serialize to JSON and back, with different indent settings.
{
"name": "Alice",
"age": 30,
"admin": True,
"tags": [
"python",
"backend"
]
}{
"name": "Alice",
"age": 30,
"admin": true,
"tags": [
"python",
"backend"
]
}CSV files
Python's csv module handles quoting, escaping, and different delimiters correctly. Do not split CSV lines on commas manually, quoted fields with embedded commas will break it.
1import csv23# Read with csv.reader, rows are lists of strings4with open("scores.csv", encoding="utf-8") as f:5 reader = csv.reader(f)6 header = next(reader) # skip the header row7 for row in reader:8 name, score = row[0], int(row[1])9 print(f"{name}: {score}")1011# Read with DictReader, rows are dicts keyed by header12with open("scores.csv", encoding="utf-8") as f:13 for row in csv.DictReader(f):14 print(row["name"], row["score"]) # row is a dict
Writing CSV
1import csv23rows = [4 ["Alice", 92, "A"],5 ["Bob", 78, "C+"],6 ["Carol", 85, "B"],7]89# csv.writer handles quoting and newlines10with open("results.csv", "w", newline="", encoding="utf-8") as f:11 writer = csv.writer(f)12 writer.writerow(["name", "score", "grade"]) # header13 writer.writerows(rows) # all data rows1415# DictWriter, write dicts16students = [17 {"name": "Alice", "score": 92},18 {"name": "Bob", "score": 78},19]20with open("students.csv", "w", newline="", encoding="utf-8") as f:21 writer = csv.DictWriter(f, fieldnames=["name", "score"])22 writer.writeheader()23 writer.writerows(students)
Always pass newline="" when opening a file for csv.writer. Without it, Windows adds an extra blank line between each row.