Skip to main content

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 at src to dst. If dst is a directory, the file will be copied into that directory with the same filename. If dst 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 to shutil.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 over os.path for its object-oriented approach.