Reading and writing text, pathlib, CSV with the csv module, JSON encode/decode, and binary files.
from pathlib import Path
import csv, json
Path("demo.txt").write_text("line one\nline two\n", encoding="utf-8")
Path("people.csv").write_text("name,age\nAda,36\nLinus,28\n", encoding="utf-8")
Path("data.json").write_text('{"name": "Ada", "tags": ["math", "code"]}', encoding="utf-8")with open("demo.txt", encoding="utf-8") as f:
text = f.read()Whole file as one string; with closes it even on error.
with open("demo.txt") as f:
for line in f:
print(line.rstrip("\n"))Line by line, memory-friendly; lines keep their newline.
with open("demo.txt") as f:
lines = f.read().splitlines()List of lines without newlines → ['line one', 'line two'].
with open("demo.txt") as f:
first = f.readline(); rest = f.readlines()One line, then the remaining lines as a list.
with open("out.txt", "w", encoding="utf-8") as f:
f.write("hello\n")
f.writelines(["a\n", "b\n"])'w' truncates or creates; write returns the character count.
with open("out.txt", "a") as f:
print("appended", file=f)'a' appends; print(file=...) adds the newline for you.
with open("fresh.txt", "x") as f:
f.write("new")'x' creates only; FileExistsError if the file is already there.
with open("demo.txt") as src, open("copy.txt", "w") as dst:
dst.write(src.read())Two files in one with statement.
Path("demo.txt").read_text(encoding="utf-8")Open, read, close in one call; write_text is the mirror.
p = Path("data") / "raw" / "file.tar.gz"/ joins path parts on any OS.
p.name, p.stem, p.suffix, p.suffixes, p.parent'file.tar.gz', 'file.tar', '.gz', ['.tar', '.gz'], 'data/raw'.
Path("demo.txt").exists(), Path("demo.txt").is_file(), Path(".").is_dir()→ True, True, True.
Path("data/raw").mkdir(parents=True, exist_ok=True)mkdir -p.
sorted(Path(".").glob("*.txt")), list(Path(".").rglob("*.csv"))Pattern match in this dir / recursively.
Path.cwd(), Path.home(), Path("demo.txt").resolve()Working dir, home dir, absolute path.
Path("demo.txt").stat().st_sizeSize in bytes; st_mtime is the modified time.
Path("demo.txt").with_suffix(".md"), Path("demo.txt").with_name("other.txt")Derive a sibling path.
import shutil
shutil.copy("demo.txt", "backup.txt"); shutil.rmtree("data", ignore_errors=True)Copy a file; delete a whole directory tree.
import tempfile
with tempfile.TemporaryDirectory() as tmp:
(Path(tmp) / "t.txt").write_text("x")A scratch directory that is removed on exit.
Path("demo.txt").rename("renamed.txt"); Path("renamed.txt").unlink(missing_ok=True)Move/rename, then delete.
with open("people.csv", newline="") as f:
rows = list(csv.reader(f))List of lists of strings, header included. Always newline=''.
with open("people.csv", newline="") as f:
people = list(csv.DictReader(f))One dict per row, keyed by the header → [{'name': 'Ada', 'age': '36'}, ...].
with open("out.csv", "w", newline="") as f:
w = csv.writer(f)
w.writerow(["name", "age"])
w.writerows([["Ada", 36], ["Linus", 28]])Quoting and escaping handled for you.
with open("out.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["name", "age"])
w.writeheader()
w.writerow({"name": "Ada", "age": 36})Write from dicts; missing keys raise unless restval is set.
with open("people.csv", newline="") as f:
list(csv.reader(f, delimiter=";", quotechar="'"))Other dialects: change the delimiter and quote character.
int(people[0]["age"]) + 1CSV gives strings; convert numbers yourself (or use pandas).
json.dumps({"a": 1, "b": [1, 2], "c": None})Python → JSON text: '{"a": 1, "b": [1, 2], "c": null}'.
json.dumps({"b": 1, "a": 2}, indent=2, sort_keys=True)Pretty-print with sorted keys.
json.loads('{"a": 1, "ok": true}')JSON text → Python → {'a': 1, 'ok': True}.
with open("data.json") as f:
data = json.load(f)Read a JSON file → dict.
with open("out.json", "w") as f:
json.dump(data, f, indent=2)Write a JSON file.
json.dumps((1, 2)), json.loads(json.dumps((1, 2)))Tuples become lists and stay lists on the way back.
import datetime as dt
json.dumps({"when": dt.date(2026, 9, 26)}, default=str)Non-JSON types raise TypeError unless default= converts them.
json.dumps({"city": "Zürich"}, ensure_ascii=False)Keep non-ASCII characters instead of \u escapes.
try:
json.loads("{bad json}")
except json.JSONDecodeError as e:
print(e.msg, e.lineno, e.colno)Malformed input raises JSONDecodeError (a ValueError).
data.get("tags", [])[0] if data.get("tags") else NoneRead nested JSON defensively — keys and lists may be missing.
with open("blob.bin", "wb") as f:
f.write(b"\x00\x01\xff")
Path("blob.bin").read_bytes()'b' modes move bytes, not str.
with open("demo.txt", "rb") as f:
f.seek(5); f.read(3), f.tell()Jump to byte 5, read 3, report the position.
import pickle
blob = pickle.dumps({"a": (1, 2)}); pickle.loads(blob)Any Python object ↔ bytes; never unpickle untrusted data.
import gzip
with gzip.open("demo.txt.gz", "wt") as f:
f.write("compressed text")Compressed text files; 'rt' to read them back.
import os
os.listdir("."), os.path.join("a", "b.txt"), os.path.getsize("demo.txt")The older os.path API; pathlib covers the same ground.
Want the topic explained, not just listed? The JSON lesson walks through it with graded exercises. Preparing for interviews? See the interview prep track.