Copy files and directory trees in Python
Use shutil.copy, copy2, and copytree, understand metadata limits and overwrites, and handle errors without treating a file copy as a complete backup.
Use shutil.copy() for file content and permission bits, shutil.copy2() when you also want supported metadata copied, and shutil.copytree() for a directory tree.
Copy one file
from pathlib import Path
import shutil
source = Path("input/report.txt")
destination = Path("output/report.txt")
destination.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(source, destination)
The source must exist. If the destination is an existing directory, copy() uses the source's filename inside it. If it names an existing file, that file is replaced. Make the overwrite behavior deliberate.
Preserve supported metadata
shutil.copy2(source, destination)
copy2() attempts to preserve metadata such as permission bits and timestamps. It cannot preserve everything on every platform: ownership, access-control lists, and platform-specific data can require separate handling. It is useful for file-copy workflows but does not by itself provide a complete backup or a consistent snapshot of a changing file.
Copy a directory tree
shutil.copytree("input/project", "output/project")
The destination must normally be absent. On Python 3.8 and later, dirs_exist_ok=True permits existing destination directories:
shutil.copytree("input/project", "output/project", dirs_exist_ok=True)
This can overwrite destination files with matching names; it does not remove unrelated files already there. By default, symbolic links are followed and their targets copied. Review symlinks=True if preserving links is required.
| Function | Content | Additional behavior |
|---|---|---|
copyfile() |
One file | Does not copy permission bits or timestamps |
copy() |
One file | Copies permission bits |
copy2() |
One file | Attempts to copy supported metadata |
copytree() |
A directory tree | Uses copy2() for files by default and copies directory metadata |
FAQ
Will a large file be loaded entirely into memory? These functions do not ordinarily read the entire file into a Python buffer. Depending on the platform, Python can use operating-system fast-copy operations or buffered copying. Avoid assuming one fixed buffer size or a universal memory guarantee.
How should I build portable paths? Pass pathlib.Path objects, as above, or construct paths with os.path.join().
Which errors should I handle? Common cases include a missing source (FileNotFoundError), insufficient access (PermissionError), and copying a file onto itself (shutil.SameFileError). A failed copy may leave partial output; successful return is not proof of an atomic replacement or durable storage.
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan