pathlib for files and directories

Python · Practical · 8 min

Path handling with string concatenation breaks across operating systems; pathlib doesn't.

pathlib.Path represents a filesystem path as an object, replacing most of os.path. Join parts with the / operator: Path("data") / "raw" / "users.csv". Python picks the right separator for the operating system, so the same code works on Windows and Linux.

Pure path manipulation, with no disk access:

  • p.name (users.csv), p.stem (users), p.suffix (.csv), p.parent
  • p.with_suffix(".json"), p.with_name("other.csv")
  • p.resolve() makes it absolute; Path.home() and Path.cwd() give common anchors

Querying and changing the filesystem:

  • p.exists(), p.is_file(), p.is_dir(), p.stat().st_size
  • p.mkdir(parents=True, exist_ok=True) creates a directory tree without failing if it exists
  • p.read_text(encoding="utf-8"), p.write_text(...), read_bytes, write_bytes for quick whole-file I/O
  • p.open() for streaming, used exactly like built-in open
  • p.unlink(missing_ok=True) deletes a file; p.rename(target) moves it

Find files with p.iterdir() (direct children), p.glob("*.csv"), and recursive p.rglob("*.py"). Python 3.12 added Path.walk(), a pathlib equivalent of os.walk. For copying and removing trees, shutil.copytree and shutil.rmtree accept Path objects.

Most standard-library and third-party functions accept any path-like object, so you rarely need str(p). Prefer accepting str | Path in your own APIs and converting once with Path(arg).

Example

from pathlib import Path
import tempfile

root = Path(tempfile.mkdtemp())
reports = root / "out" / "reports"
reports.mkdir(parents=True, exist_ok=True)

for month in ["jan", "feb"]:
    (reports / f"{month}.csv").write_text("id,total\n1,10\n", encoding="utf-8")

for p in sorted(reports.glob("*.csv")):
    print(p.name, p.stem, p.suffix, p.stat().st_size)
# feb.csv feb .csv 14
# jan.csv jan .csv 14

target = reports / "jan.csv"
print(target.with_suffix(".json").name)    # jan.json
print(target.relative_to(root))            # out/reports/jan.csv
print(len(list(root.rglob("*.csv"))))      # 2

Remember

  • Join paths with /; pathlib handles OS separators
  • .name, .stem, .suffix, .parent take paths apart
  • glob/rglob find files; read_text/write_text for quick I/O

Watch out for

  • Building paths with string concatenation and hard-coded / or \.

Check yourself

  1. What is `Path("docs/report.final.pdf").stem`?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/pathlib.html