Pathlib Module

Python Modules

Python pathlib Module

In this tutorial, we'll use pathlib to work with file and folder paths, check files, create folders, and read or write content.

The pathlib module represents filesystem paths as objects. It provides a readable, cross-platform alternative to manually joining path strings.

pathlib is part of Python's standard library:

from pathlib import Path

Creating Path objects

Create a path without opening or creating the file:

from pathlib import Path

report = Path("reports") / "2026" / "july.csv"
print(report)

On macOS and Linux the output is:

reports/2026/july.csv

The / operator joins path components using the correct separator for the operating system.

root = Path("data")
filename = "scores.json"
path = root / filename

This is clearer and safer than building paths with string concatenation.

Relative and absolute paths

A relative path is interpreted from the program's current working directory:

from pathlib import Path

path = Path("notes.txt")

print(path.is_absolute())
print(Path.cwd())

Resolve a path to an absolute path with .resolve():

absolute_path = path.resolve()
print(absolute_path)

.resolve() does not make a relative path portable between machines. Avoid hard-coding paths such as /Users/name/project or C:\\Users\\name\\project when your program needs to run elsewhere.

Inspecting path components

Path objects expose useful attributes:

from pathlib import Path

path = Path("reports/2026/july.csv")

print(path.name)
print(path.stem)
print(path.suffix)
print(path.parent)
print(path.parts)

Output on a POSIX system:

july.csv
july
.csv
reports/2026
('reports', '2026', 'july.csv')

For a name such as archive.tar.gz, .suffix is .gz and .suffixes is ['.tar', '.gz'].

Changing a name or extension

Path methods return new objects; they do not rename files on disk unless the method explicitly performs a filesystem operation.

from pathlib import Path

original = Path("reports/july.csv")

print(original.with_suffix(".json"))
print(original.with_name("august.csv"))
reports/july.json
reports/august.csv

Checking whether paths exist

Use these methods when your logic depends on the filesystem:

from pathlib import Path

path = Path("settings.json")

print(path.exists())
print(path.is_file())
print(path.is_dir())

The filesystem can change between a check and the next operation. When reading a file, you should still be prepared to handle FileNotFoundError or PermissionError.

Creating directories

Create one directory with .mkdir():

from pathlib import Path

Path("output").mkdir(exist_ok=True)

Create missing parent directories as well:

Path("output/reports/2026").mkdir(parents=True, exist_ok=True)
  • parents=True creates missing intermediate directories.
  • exist_ok=True avoids an error when the directory already exists.

Do not use exist_ok=True automatically when an existing directory would indicate a genuine problem.

Reading and writing text

For small text files, Path has convenient methods:

from pathlib import Path

path = Path("message.txt")
path.write_text("Hello from pathlib\n", encoding="utf-8")

content = path.read_text(encoding="utf-8")
print(content)

Specify the encoding rather than relying on an operating-system default.

These methods read or write the whole file. For large files or line-by-line processing, use open():

from pathlib import Path

path = Path("large-log.txt")

with path.open("r", encoding="utf-8") as file:
    for line in file:
        print(line.rstrip())

Working with bytes

Use .read_bytes() and .write_bytes() for binary data:

from pathlib import Path

source = Path("image.png")
data = source.read_bytes()

Path("image-copy.png").write_bytes(data)

For large binary files, stream the data instead of loading the whole file into memory.

Finding files with glob

.glob() searches from a directory:

from pathlib import Path

project = Path(".")

for path in project.glob("*.py"):
    print(path)

Use .rglob() or the ** pattern to search recursively:

for path in project.rglob("*.py"):
    print(path)

The order returned by the filesystem is not guaranteed. Sort when order matters:

python_files = sorted(project.rglob("*.py"))

Iterating over a directory

.iterdir() returns the immediate contents of a directory:

from pathlib import Path

for item in Path(".").iterdir():
    kind = "directory" if item.is_dir() else "file"
    print(item.name, kind)

It does not search subdirectories recursively.

Moving, renaming, and deleting

These methods change the filesystem:

from pathlib import Path

draft = Path("draft.txt")
published = Path("published.txt")

draft.rename(published)

Delete a file with .unlink() and an empty directory with .rmdir():

published.unlink(missing_ok=True)
Path("empty-folder").rmdir()

Use destructive methods carefully. .rmdir() deliberately refuses to remove a non-empty directory.

A practical example: group files by extension

from collections import defaultdict
from pathlib import Path


def group_by_extension(folder):
    groups = defaultdict(list)

    for path in Path(folder).iterdir():
        if path.is_file():
            suffix = path.suffix.lower() or "[no extension]"
            groups[suffix].append(path.name)

    return {
        suffix: sorted(names)
        for suffix, names in groups.items()
    }

This example keeps Path objects while inspecting files and converts to names only for the final result.

Common pathlib mistakes

  • Converting every Path to a string too early.
  • Joining components with + instead of /.
  • Assuming a relative path is relative to the Python file rather than the current working directory.
  • Omitting an explicit text encoding.
  • Assuming .glob() returns results in alphabetical order.
  • Using .exists() as a substitute for handling filesystem errors.
  • Forgetting that methods such as .unlink() and .rename() change real files.

Practice

1. Build reports/2026/summary.txt from three separate values. 2. Return a file's name, stem, and lowercase suffix. 3. Find every .py file below a project directory. 4. Read a UTF-8 text file and count its non-empty lines. 5. Create an output directory and change a path's extension to .json.

Continue with the [interactive Python coding exercises](/codingexercises), including the premium Pathlib practice pack.