How to Rename Hundreds of Files in Seconds with Python
Introduction
Renaming files is one of the most common automation tasks in everyday computer work. It sounds simple until you need to rename 300 photos, clean up downloaded files, or standardize messy filenames from different sources.
Typical situations include:
- Cleaning up chaotic filenames in a Downloads folder
- Adding date prefixes to invoices or reports
- Replacing spaces with underscores
- Removing unwanted characters from filenames
- Renaming exported screenshots or camera images
Doing this manually is slow and error-prone. With Python, you can rename hundreds of files in seconds using only a few lines of code.
In this tutorial, you will learn how to:
- Rename a single file
- Rename all files in a folder
- Add prefixes and suffixes
- Replace characters in filenames
- Apply custom batch renaming rules
- Avoid dangerous mistakes when working with real files
All examples are tested on Python 3.12.
Two Ways to Rename: os vs pathlib
Python provides two common ways to rename files:
| Method | Style |
|---|---|
os.rename() | Traditional and straightforward |
pathlib.Path.rename() | Modern and easier to read |
Using os.rename()
import os
os.rename("old.txt", "new.txt")
Using pathlib
from pathlib import Path
Path("old.txt").rename("new.txt")
Both approaches work well. The main difference is readability and convenience. This tutorial mainly uses pathlib because it provides cleaner syntax and better path handling. You will still see equivalent os examples when useful.
Renaming a Single File
Let’s start with the simplest case: renaming one file.
Suppose your project folder contains:
report.txt
You want to rename it to:
monthly_report.txt
Basic Example
from pathlib import Path
old_file = Path("report.txt")
new_file = Path("monthly_report.txt")
old_file.rename(new_file)
print("File renamed successfully")
Expected output:
File renamed successfully
This code renames the file in the current working directory.
Relative vs Absolute Paths
You can use either relative or absolute paths.
Relative path — refers to a file in the current working directory:
Path("report.txt")
Absolute path — works regardless of where the script runs from:
Path("C:/Users/Alex/Documents/report.txt")
Absolute paths are safer when scripts may be run from different locations.
What Happens If the Target Already Exists?
Behavior depends on the operating system. On some systems, renaming may overwrite the destination file. On others, it may raise an error.
Safer approach:
from pathlib import Path
source = Path("report.txt")
target = Path("monthly_report.txt")
if target.exists():
print("Target file already exists")
else:
source.rename(target)
Always check before renaming important files.
Renaming All Files in a Folder
Batch renaming becomes much more useful when processing entire directories.
Example 1: Rename All .txt Files to .md
Suppose a folder contains:
notes.txt
tasks.txt
ideas.txt
You want to convert them into Markdown filenames.
from pathlib import Path
folder = Path("documents")
for file in folder.glob("*.txt"):
new_name = file.with_suffix(".md")
file.rename(new_name)
print(f"{file.name} -> {new_name.name}")
Expected output:
notes.txt -> notes.md
tasks.txt -> tasks.md
ideas.txt -> ideas.md
glob("*.txt") filters only .txt files.
Example 2: Add IMG_ Prefix to Photos
Suppose your folder contains:
beach.jpg
sunset.jpg
family.jpg
You want camera-style filenames:
IMG_beach.jpg
IMG_sunset.jpg
IMG_family.jpg
Script:
from pathlib import Path
folder = Path("photos")
for file in folder.glob("*.jpg"):
new_name = file.with_name(f"IMG_{file.name}")
file.rename(new_name)
print(f"Renamed: {new_name.name}")
Expected output:
Renamed: IMG_beach.jpg
Renamed: IMG_sunset.jpg
Renamed: IMG_family.jpg
This pattern is common when organizing exported images or phone backups.
iterdir() vs glob() vs rglob()
These three methods iterate through files but behave differently.
| Method | Behavior | When to Use |
|---|---|---|
iterdir() | All files and subdirectories in current folder | Simple traversal, no filter needed |
glob("*.jpg") | Files matching a pattern in current folder | Filter by extension or name |
rglob("*.jpg") | Files matching a pattern in ALL subfolders | Recursive search |
In most batch renaming scripts, glob() is the most convenient option. rglob() becomes useful when files are spread across nested directories.
Common Real-World Patterns
Here are several renaming patterns that appear frequently in real automation tasks.
Pattern 1: Add a Date Prefix
Original files:
invoice.pdf
report.docx
Desired result:
2026-05-15_invoice.pdf
2026-05-15_report.docx
Script:
from pathlib import Path
from datetime import date
folder = Path("documents")
today = date.today().isoformat()
for file in folder.iterdir():
if file.is_file():
new_name = f"{today}_{file.name}"
file.rename(file.with_name(new_name))
print(new_name)
Expected output:
2026-05-15_invoice.pdf
2026-05-15_report.docx
This is useful for reports, backups, invoices, and exported datasets.
Pattern 2: Replace Spaces with Underscores
Original files:
My File.pdf
Sales Report.xlsx
Desired result:
My_File.pdf
Sales_Report.xlsx
Script:
from pathlib import Path
folder = Path("downloads")
for file in folder.iterdir():
if file.is_file():
clean_name = file.name.replace(" ", "_")
file.rename(file.with_name(clean_name))
print(clean_name)
Expected output:
My_File.pdf
Sales_Report.xlsx
Replacing spaces is especially useful for web uploads, scripts, and command-line compatibility.
Pattern 3: Rename Files Sequentially
Original files:
photo.jpg
image.jpg
pic.jpg
Desired result:
001.jpg
002.jpg
003.jpg
Script:
from pathlib import Path
folder = Path("images")
files = list(folder.glob("*.jpg"))
for index, file in enumerate(files, start=1):
new_name = f"{index:03}.jpg"
file.rename(file.with_name(new_name))
print(f"{file.name} -> {new_name}")
Expected output:
photo.jpg -> 001.jpg
image.jpg -> 002.jpg
pic.jpg -> 003.jpg
{index:03} pads numbers with zeros.
Pattern 4: Remove Specific Characters
Original files:
file(1).txt
notes(backup).txt
Desired result:
file1.txt
notesbackup.txt
Script:
from pathlib import Path
folder = Path("files")
for file in folder.iterdir():
if file.is_file():
clean_name = (
file.name
.replace("(", "")
.replace(")", "")
)
file.rename(file.with_name(clean_name))
print(clean_name)
Expected output:
file1.txt
notesbackup.txt
This is useful when cleaning filenames exported by browsers or cloud storage systems. The is_file() check prevents accidentally renaming folders whose names also contain those characters.
Pattern 5: Change File Extensions
Original files:
photo1.jpeg
photo2.jpeg
Desired result:
photo1.jpg
photo2.jpg
Script:
from pathlib import Path
folder = Path("photos")
for file in folder.glob("*.jpeg"):
new_file = file.with_suffix(".jpg")
file.rename(new_file)
print(new_file.name)
Expected output:
photo1.jpg
photo2.jpg
Changing extensions is common when standardizing media libraries.
Pattern 6: Convert All Filenames to Lowercase
Useful when consistency matters — for example, before deploying assets to a web server, or when filenames mix uppercase and lowercase from different sources.
Original files:
README.md
Photo.JPG
DATA.csv
Desired result:
readme.md
photo.jpg
data.csv
Script:
from pathlib import Path
folder = Path("project")
for file in folder.iterdir():
if file.is_file():
new_name = file.name.lower()
if new_name != file.name:
file.rename(file.with_name(new_name))
print(f"{file.name} -> {new_name}")
Expected output:
README.md -> readme.md
Photo.JPG -> photo.jpg
DATA.csv -> data.csv
The if new_name != file.name check skips files that are already lowercase, which avoids unnecessary rename operations.
Safety Tips: Don’t Lose Your Files
File renaming scripts can accidentally damage large directories very quickly. A small bug can rename thousands of files incorrectly in seconds. Here are some important safety practices.
Always Start with a Dry Run
Instead of renaming immediately, print the planned changes first.
Risky:
file.rename(new_name)
Safer:
print(f"{file.name} -> {new_name.name}")
Verify the output before making actual changes.
Test on a Copy Folder First
Never test directly on:
- Work documents
- Family photos
- Production backups
Create a duplicate test folder first.
Avoid Overwriting Existing Files
Always check whether the destination already exists.
if not new_path.exists():
file.rename(new_path)
Otherwise, files may be replaced accidentally.
Avoid Cloud Sync Folders
Be careful with:
- OneDrive
- iCloud Drive
- Google Drive
- Dropbox
Running aggressive rename scripts inside synced folders can create sync conflicts or duplicate files.
Add a Confirmation Prompt
Simple confirmation prompts prevent many mistakes.
Example: Safe Batch Rename Script
from pathlib import Path
folder = Path("downloads")
planned_changes = []
for file in folder.glob("*.txt"):
new_name = file.with_name(
file.stem.replace(" ", "_") + file.suffix
)
planned_changes.append((file, new_name))
print("Planned changes:")
for old, new in planned_changes:
print(f"{old.name} -> {new.name}")
confirm = input("Continue? (y/n): ")
if confirm.lower() == "y":
for old, new in planned_changes:
try:
if new.exists():
print(f"Skipped (exists): {new.name}")
continue
old.rename(new)
print(f"Renamed: {new.name}")
except Exception as e:
print(f"Error: {e}")
else:
print("Operation cancelled")
This script includes:
- Dry-run preview
- Confirmation prompt
- File existence checks
- Exception handling
These practices matter when working with real data.
Renaming Files Recursively (Including Subfolders)
Sometimes files are spread across nested folders. Path.rglob() searches recursively through all subdirectories.
Example: Clean Up System Junk Files
Some operating systems create hidden files that clutter your project folders — macOS creates .DS_Store, and Windows creates Thumbs.db and desktop.ini. This script finds and removes them across an entire project directory.
First, do a dry-run to see what will be deleted:
from pathlib import Path
project = Path("my_project")
patterns = [".DS_Store", "Thumbs.db", "desktop.ini"]
for pattern in patterns:
for file in project.rglob(pattern):
print(file)
After verifying the list looks correct, run the deletion:
from pathlib import Path
project = Path("my_project")
patterns = [".DS_Store", "Thumbs.db", "desktop.ini"]
for pattern in patterns:
for file in project.rglob(pattern):
file.unlink()
print(f"Deleted: {file}")
Expected output:
Deleted: my_project/assets/.DS_Store
Deleted: my_project/docs/Thumbs.db
Recursive operations are powerful but dangerous. Always dry-run first.
Beyond Renaming: Pathlib for File Management
pathlib is useful far beyond renaming. It can also:
- Create directories
- Delete files
- Move files
- Read file metadata (size, modification time)
- Traverse folders
Example: read file metadata.
from pathlib import Path
from datetime import datetime
file = Path("report.pdf")
size_kb = file.stat().st_size / 1024
modified = datetime.fromtimestamp(file.stat().st_mtime)
print(f"Size: {size_kb:.1f} KB")
print(f"Modified: {modified}")
Expected output:
Size: 200.0 KB
Modified: 2026-05-15 14:23:01
You can build complete file management automation pipelines using only Python’s standard library.
Wrap-Up
Python makes large-scale file renaming surprisingly simple. With pathlib, you can clean filenames, organize photos, standardize extensions, and automate repetitive folder management tasks with very little code.
The most important habit is safety: always start with a dry-run before performing actual renames.
Try these examples on a test folder first, then adapt them to your own workflow. For questions or future automation topics, get in touch via the Contact page.
You may also be interested in automating email delivery with Python, which pairs well with file renaming scripts — for example, automatically renaming a generated report and emailing it to a team.