runtime
94 / 250
lesson 94 Files & Directories · intermediate

Paths and folders with pathlib

`Path` objects join folder and file names with `/`, take names apart, create folders, read and write whole files, and list a folder's files with `glob`.

You'll be able to
  • Join path pieces with / and read a path's name, stem and suffix
  • Create folders with mkdir(parents=True, exist_ok=True) and check files with exists()
  • List the files that match a pattern with glob, in a predictable order
The idea

So far a path has been a string like "out/delivered.txt". Strings work until you need to take a path apart (what's the file's extension?), join pieces safely, or ask questions (does this file exist? which files are in this folder?).

from pathlib import Path gives you Path objects. / joins pieces: Path("exports") / "orders.csv". A path knows its name (orders.csv), stem (orders) and suffix (.csv), can check exists(), create a folder with mkdir, and read or write a whole small file with read_text and write_text (each takes encoding= like open).

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · Build a path and take it apart
from pathlib import Path

report = Path("exports") / "2024-12" / "orders.csv"
print(report)
print(report.name, report.stem, report.suffix)
print(report.exists())

folder = Path("exports") / "2024-12"
folder.mkdir(parents=True, exist_ok=True)
report.write_text("order_id,total\nO108024,57.34\n", encoding="utf-8")
print(report.exists(), report.read_text(encoding="utf-8").splitlines())
example-2.py · Writing into a folder that doesn't exist
from pathlib import Path

Path("archive/2023/orders.csv").write_text("order_id,total\n", encoding="utf-8")

folder.glob("*.csv") finds the files in folder whose names match the pattern: * stands for any run of characters. The order it finds them in depends on the system, so wrap it in sorted(...) whenever order matters. This function reports how many data rows (lines after the header) each daily export has.

example-3.py · Rows in each daily export
from pathlib import Path

def rows_per_file(folder):
    counts = {}
    for path in sorted(Path(folder).glob("*.csv")):
        lines = path.read_text(encoding="utf-8").splitlines()
        counts[path.name] = len(lines) - 1
    return counts

exports = Path("exports")
exports.mkdir(exist_ok=True)
(exports / "2024-01-03.csv").write_text("order_id\nO100043\n", encoding="utf-8")
(exports / "2024-03-13.csv").write_text("order_id\nO101217\nO101300\n", encoding="utf-8")
(exports / "notes.txt").write_text("sent to finance\n", encoding="utf-8")
print(rows_per_file("exports"))

When to use it: whenever your program builds paths, checks for files, or works through a folder. Path objects can be passed to open too. Mistakes to avoid: gluing strings together and forgetting the /, assuming glob returns files in a useful order, and writing into a folder you haven't created.

Review
  • Path("a") / "b.csv" builds a path; name, stem and suffix take it apart.
  • mkdir(parents=True, exist_ok=True) creates folders; writing a file never creates them.
  • glob("*.csv") finds matching files; sort the result when order matters.
  • Next: what text looks like on disk, as bytes, and what happens when the encoding is wrong.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Paths and folders with pathlib — Files & Directories · Runtime