---
title: Use pathlib Instead of os.path for File Operations
impact: MEDIUM
impactDescription: os.path functions return plain strings that are easy to misuse; pathlib.Path provides an object-oriented, composable, and cross-platform API that eliminates common path manipulation bugs.
tags: python, pathlib, os-path, files, quality, python3
---

## Use pathlib Instead of os.path for File Operations

Python 3.4 introduced `pathlib.Path` as a modern, object-oriented replacement for `os.path`. Paths are represented as objects supporting `/` operator for joining, `.stem`, `.suffix`, `.parent` for decomposition, and `.read_text()` / `.write_text()` for content — with no risk of forgetting `os.path.join` and accidentally concatenating strings.

**Incorrect:**
```python
import os

# String concatenation — silent bugs on Windows with backslashes
config_path = base_dir + "/config/" + "settings.json"

# Verbose os.path usage
import os.path

full_path = os.path.join(base_dir, "config", "settings.json")
file_name = os.path.basename(full_path)
dir_name  = os.path.dirname(full_path)
stem      = os.path.splitext(file_name)[0]
ext       = os.path.splitext(file_name)[1]

if os.path.exists(config_path):
    with open(config_path, encoding="utf-8") as f:
        content = f.read()

os.makedirs(os.path.join(base_dir, "logs"), exist_ok=True)
```

**Correct:**
```python
from pathlib import Path

base_dir = Path("/app")

# / operator for joining — cross-platform and clear
config_path = base_dir / "config" / "settings.json"

# Readable decomposition
file_name = config_path.name        # "settings.json"
dir_name  = config_path.parent      # Path("/app/config")
stem      = config_path.stem        # "settings"
ext       = config_path.suffix      # ".json"

# Built-in existence check and file reading
if config_path.exists():
    content = config_path.read_text(encoding="utf-8")

# Directory creation
(base_dir / "logs").mkdir(parents=True, exist_ok=True)

# Glob for files
for py_file in base_dir.rglob("*.py"):
    print(py_file)
```

**Tools:** Ruff `PTH100`–`PTH208` (flake8-use-pathlib), pyupgrade, SonarQube Python rules
