Python Filesystem & Pathlib Operations
Modern Python (PEP 428) replaces legacy string path concatenation (os.path.join()) with pathlib.Path, treating paths as rich, platform-independent objects.
Key Path Properties:
path.name: Full filename with extension ("report.pdf").path.stem: Filename without extension ("report").path.suffix: File extension (".pdf").path.parent: Immediate parent directory object.path.resolve(): Absolute canonical filesystem path resolving symlinks.
from pathlib import Path
# Constructing cross-platform paths using the / slash operator:
project_dir = Path("my_enterprise_app")
sub_path = project_dir / "src" / "controllers" / "auth_controller.py"
print("Full Path String: ", sub_path)
print("Filename (name): ", sub_path.name)
print("Filename stem: ", sub_path.stem)
print("Extension (suffix):", sub_path.suffix)
print("Parent Directory: ", sub_path.parent)
print("Grandparent Dir: ", sub_path.parent.parent)
pathlib automatically renders forward slashes on Linux/macOS and backslashes on Windows without any conditional platform code.
Creating folders manually can crash if the parent folders do not exist, or if the folder already exists. pathlib.Path.mkdir() solves this cleanly with two critical flags:
parents=True: Automatically creates all missing intermediate parent directories (likemkdir -pin Unix).exist_ok=True: Does not crash if the target folder already exists!
from pathlib import Path
# Define a deeply nested target folder:
backup_folder = Path("backups") / "2026" / "august" / "database_dumps"
# Create nested directory tree in ONE line safely:
backup_folder.mkdir(parents=True, exist_ok=True)
print(f"โ
Verified / Created directory: {backup_folder}")
print("Does folder exist?", backup_folder.exists())
print("Is it a directory?", backup_folder.is_dir())
Always pass parents=True, exist_ok=True when preparing upload or log folders to ensure idempotent script execution.
Perform complete CRUD operations on files using built-in Path methods:
path.exists(): ReturnsTrueif file or folder exists.path.is_file()/path.is_dir(): Type verification.path.rename(new_path): Renames or moves file to a new path.path.unlink(missing_ok=True): Deletes a file (withmissing_ok=Trueto prevent errors if already deleted!).path.rmdir(): Deletes an empty directory.
from pathlib import Path
temp_file = Path("temporary_draft.txt")
# 1. Write text directly to file with write_text():
temp_file.write_text("This is temporary draft content.", encoding="utf-8")
print(f"1. Created {temp_file.name} | Exists? {temp_file.exists()}")
# 2. Rename / Move file:
archived_file = Path("archived_draft.txt")
temp_file.rename(archived_file)
print(f"2. Renamed to {archived_file.name} | Old exists? {temp_file.exists()}")
# 3. Read back text directly with read_text():
content = archived_file.read_text(encoding="utf-8")
print(f"3. Read content: '{content}'")
# 4. Clean up / Delete file with unlink():
archived_file.unlink(missing_ok=True)
print(f"4. Deleted file | Exists? {archived_file.exists()}")
Path.write_text() and Path.read_text() encapsulate opening, encoding, reading/writing, and closing files into a single, clean line of code!
Search across your entire project folder hierarchy using recursive pattern matching:
path.glob("*.py"): Searches matching files in the current folder only.path.rglob("*.py"): Recursive Glob โ searches the current directory AND all nested sub-folders at any depth!
from pathlib import Path
# Search current workspace for all HTML tutorial files:
workspace = Path(".")
html_files = list(workspace.glob("*.html"))
print(f"๐ Found {len(html_files)} HTML files in root folder.")
for f in html_files[:4]:
# Inspect file size in bytes:
size_kb = f.stat().st_size / 1024
print(f"โข {f.name:30} | {size_kb:.1f} KB")
Path.glob() returns a lazy generator, allowing your program to iterate through hundreds of thousands of files without loading all filenames into RAM at once.
Writing path = folder + "/" + filename can result in double slashes (folder//file) or fail on Windows if backslashes are hardcoded. Always use pathlib.Path(folder) / filename.
Use pathlib to create a folder "my_test_dir", write a file "hello.txt" inside it, read its content, and clean up both file and folder.
from pathlib import Path
test_dir = Path("my_test_dir")
test_dir.mkdir(exist_ok=True)
test_file = test_dir / "hello.txt"
test_file.write_text("Hello from Pathlib! ๐", encoding="utf-8")
print("File Content:", test_file.read_text(encoding="utf-8"))
# Cleanup:
test_file.unlink()
test_dir.rmdir()
print("Cleaned up directory successfully! โ
")
Q What is the difference between unlink() and rmdir() in pathlib?
unlink() deletes a physical file. rmdir() deletes an empty directory. If a directory contains files, rmdir() will raise an OSError (use shutil.rmtree() for recursive directory deletion).
Q Why is pathlib.Path preferred over the os.path module?
pathlib provides an object-oriented, readable interface with built-in path methods (.read_text(), .write_text(), .mkdir(), .glob()) and natural slash (/) path joining.
Q How do I convert a pathlib.Path object to a string for older third-party libraries?
Simply call str(my_path) or pass the Path object directly, as all standard Python 3.6+ functions accept Path objects seamlessly via the os.PathLike interface.