How to Copy and Rename Files in Python
This guide explains how to copy and rename files in Python, using the shutil
module. We'll cover copying and renaming a single file, creating unique filenames with timestamps, and recursively copying and renaming files within directories.
Copying and Renaming a Single File
Using shutil.copy()
(Preserves Permissions)
The shutil.copy()
function copies a file, preserving its permission bits. This is the most common and often the best approach.
from shutil import copy
import pathlib
src_path = pathlib.Path('example.txt')
destination_path = pathlib.Path('example-new.txt')
copy(src_path, destination_path) # Copy and rename
print('File copied and renamed successfully!')
- You can also use strings instead of
pathlib.Path
objects. shutil.copy(src, dst)
: Copies the file atsrc
todst
. Ifdst
is a directory, the file will be copied into that directory with the same filename. Ifdst
is a file path, the file will be copied to that path, effectively renaming it.- Permissions are preserved.
- File metadata (like creation/modification times) is not preserved.
Using shutil.copy2()
(Preserves Metadata)
If you need to preserve as much file metadata as possible (creation time, modification time, etc.), use shutil.copy2()
:
from shutil import copy2
import pathlib
src_path = pathlib.Path('example.txt')
destination_path = pathlib.Path('example-new.txt')
copy2(src_path, destination_path) # Copy, rename, and preserve metadata
print('File copied and renamed successfully!')
shutil.copy2()
is identical toshutil.copy()
except that it also attempts to preserve file metadata. This is useful for backups or archiving.
Creating Unique Filenames with Timestamps
To avoid overwriting existing files, a common practice is to include a timestamp in the filename:
from datetime import datetime
from shutil import copy2
import pathlib
src_path = pathlib.Path('example.txt')
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") # Format timestamp
destination_path = pathlib.Path(f'example-{timestamp}.txt')
copy2(src_path, destination_path)
print(f'File copied to {destination_path}')
# Example Output: File copied to example-2025-03-02_12-34-56.txt
datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
: Creates a timestamp string in the format "YYYY-MM-DD_HH-MM-SS". This is a good format for filenames because it's sortable and avoids problematic characters.f'example-{timestamp}.txt'
creates a new file.- Using string formatting allows us to create a filename with dynamic values.
Recursively Copying and Renaming Files in a Directory
To copy and rename all files (or files matching a specific pattern) within a directory, including files in subdirectories, use os.walk()
or pathlib.Path.rglob()
:
import os
from shutil import copy2
from pathlib import Path
def copy_and_rename(src, dest):
dest_path = Path(dest)
dest_path.mkdir(parents=True, exist_ok=True) # Create destination dir
for src_dir, _, files in os.walk(src):
# Construct corresponding destination directory path
rel_path = Path(src_dir).relative_to(src)
dest_dir = dest_path / rel_path
dest_dir.mkdir(parents=True, exist_ok=True) # Ensure dest dir exists
for file in files:
if file.endswith(".txt"): # Only process .txt files
src_file = Path(src_dir) / file
file_name, extension = file.rsplit('.', 1) # Split filename
updated_filename = file_name + '-new.' + extension
dest_file = dest_dir / updated_filename
copy2(src_file, dest_file)
print(f"Copied and renamed: {src_file} -> {dest_file}")
src_path = 'my-directory'
destination = 'new-directory'
copy_and_rename(src_path, destination)
- First, the
Path
object is constructed using the specified destination path. - Then, the code creates the destination folder if it does not exist.
os.walk(src)
: This function recursively walks through a directory tree. For each directory it encounters, it yields a tuple:(dirpath, dirnames, filenames)
.dirpath
: The path to the current directory.dirnames
: A list of subdirectory names in the current directory.filenames
: A list of filenames in the current directory.
Path(src_dir).relative_to(src)
: Calculates the relative path from the original source directory (src
) to the current directory (src_dir
). This is important for recreating the same directory structure in the destination.dest_path / rel_path
: Constructs the destination directory path by joining the base destination path with the relative path.dest_dir.mkdir(parents=True, exist_ok=True)
: Creates the destination directory (and any parent directories if needed).exist_ok=True
prevents an error if the directory already exists.- The code renames the
.txt
file using string operations, and copies it to the destination. - This script is more robust, handling directory creation, and uses
pathlib
for path manipulation, which is generally preferred overos.path
for its object-oriented approach.