Python Copy File From One Directory To Another

7 min read

If you want to learn how to python copy file from one directory to another, this guide will walk you through several reliable methods, from using the built‑in shutil module to leveraging the os module and even handling large files efficiently. Whether you are a beginner or an experienced developer, understanding these techniques will help you automate file management tasks and improve your Python workflows.

Introduction

Copying files between directories is a common operation in many Python scripts. Whether you are backing up data, organizing project assets, or preparing inputs for data processing pipelines, being able to move or duplicate files quickly and safely is essential. Python provides several standard‑library modules that abstract the low‑level details of file I/O, allowing you to focus on the logic of your application rather than the mechanics of reading and writing bytes.

The core modules you will use most often are os, shutil, and pathlib. Each has its own strengths and use cases, and modern Python code often blends them for clarity and robustness. In this article we will explore:

  • The basic copy operations using shutil.copy and shutil.copy2.
  • How to preserve file metadata and why shutil.copy2 is often preferred.
  • Using shutil.copyfile for raw byte‑level copying.
  • Leveraging os.rename for fast moves within the same filesystem.
  • The modern pathlib interface, which makes path manipulation more readable.
  • Strategies for copying large files in chunks to reduce memory usage.
  • Error handling and best practices to avoid common pitfalls.
  • Frequently asked questions about permissions, overwriting, symbolic links, and cross‑platform compatibility.

By the end of this guide you will have a toolbox of techniques you can apply to any file‑copying scenario, ensuring your scripts are both efficient and reliable.

Basic Copy Operations

Using shutil.copy

The shutil module is the go‑to choice for high‑level file operations. The simplest function, shutil.copy(src, dst), copies the content and permission mode of src to dst, but it does not preserve extra metadata such as timestamps or extended attributes. It works for both files and directories (when dst is a directory) Worth knowing..

import shutil
import os

src_path = r"C:\source\example.txt"
dst_dir  = r"D:\backup"

# Copy a single file
shutil.copy(src_path, dst_dir)
# Result: D:\backup\example.txt

If dst already exists, shutil.Also, copy will overwrite it without warning. For safety, you can check existence first or use a custom naming scheme.

Using shutil.copy2

When you need to keep the original file's metadata (modification time, creation time, and other attributes), use shutil.copy2. This is especially useful for scripts that depend on timestamps for versioning or logging.

shutil.copy2(src_path, dst_dir)

The function behaves like copy but internally calls shutil.copystat to replicate the source’s stat information. In practice, copy2 is the recommended default for most use cases.

Using shutil.copyfile

If you only care about the raw content and want to avoid copying permission bits, use shutil.copyfile(src, dst). It opens both files in binary mode and writes the data directly, which can be marginally faster when metadata preservation is unnecessary.

shutil.copyfile(src_path, dst_path)  # dst_path must be a full file path

Note that copyfile does not copy the file’s mode; you must set permissions manually if needed Most people skip this — try not to. No workaround needed..

Directory‑Level Copying

shutil.copytree

When the destination is a whole directory tree, shutil.Now, copytree(src_dir, dst_dir, dirs_exist_ok=True) will recursively copy all files and subdirectories. The dirs_exist_ok parameter (Python 3.8+) prevents an error if dst_dir already exists, merging the contents instead of aborting.

src_dir = r"C:\source\project"
dst_dir = r"D:\archive\project_backup"

shutil.copytree(src_dir, dst_dir, dirs_exist_ok=True)

If you need to clean the destination before copying, you can add a pre‑step that removes the target directory safely Most people skip this — try not to. No workaround needed..

Fast Moves with os.rename

If the source and destination are on the same filesystem, you can achieve a move (copy + delete) with os.Day to day, rename(src, dst). This operation is atomic, fast, and does not require reading the file content. It is ideal for reorganizing files within a single disk volume.

os.rename(src_path, dst_path)

When you need a copy‑and‑keep behavior, combine os.rename with a temporary location or duplicate the file first Practical, not theoretical..

Modern Path Handling with pathlib

Introduced in Python 3.4 and stabilized in 3.6, the pathlib module provides an object‑oriented interface to filesystem paths. It can simplify copy operations and improve code readability.

from pathlib import Path

src = Path(r"C:\source\example.txt")
dst = Path(r"D:\backup") / src.name

# Using shutil.copy with Path objects (automatically converted to strings)
shutil.copy(src, dst)

You can also chain methods for more complex manipulations, such as creating parent directories on the fly:

(dst.parent).mkdir(parents=True, exist_ok=True)
shutil.copy(src, dst)

Copying Large Files in Chunks

When dealing with large files (hundreds of megabytes or gigabytes), reading the entire content into memory can be inefficient. The shutil module internally uses buffered I/O, but you can still control the buffer size for optimal performance That's the part that actually makes a difference. Simple as that..

def copy_large_file(src, dst, chunk_size=1024*1024):  # 1 MiB chunks
    with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
        while

```python
def copy_large_file(src, dst, chunk_size=1024*1024):  # 1 MiB chunks
    with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
        while True:
            data = fsrc.read(chunk_size)
            if not data:
                break
            fdst.write(data)

Why Chunked Copying Helps

Reading a file in modest‑sized blocks keeps the process’s memory footprint low, which is especially valuable on systems with limited RAM or when copying many large files concurrently. The operating system’s page cache will still prefetch ahead, so I/O throughput remains close to the hardware limit while avoiding the occasional spike that a single‑read‑all approach can cause.

Leveraging shutil.copyfileobj

The standard library already offers a battle‑tested helper that does exactly what the loop above implements:

shutil.copyfileobj(open(src, 'rb'), open(dst, 'wb'), length=chunk_size)

copyfileobj accepts any file‑like objects, making it easy to plug in compressed streams, network sockets, or io.BytesIO buffers without rewriting the core logic.

Adding Progress Feedback

For long‑running copies, a visual progress indicator improves user experience. Pairing tqdm with a custom read wrapper yields a concise solution:

from tqdm import tqdm

def copy_with_progress(src, dst, chunk_size=1024*1024):
    total_size = os.read(chunk_size)
            if not data:
                break
            fdst.path.basename(src)) as pbar:
        while True:
            data = fsrc.getsize(src)
    with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst, \
         tqdm(total=total_size, unit='B', unit_scale=True, desc=os.Think about it: path. write(data)
            pbar.

The wrapper updates the progress bar after each chunk, giving an accurate estimate of remaining time and throughput.

### Handling Symlinks and Special Files  
When copying directory trees, you may want to preserve symbolic links rather than dereferencing them. `shutil.copytree` supports this via the `symlinks` flag:

```python
shutil.copytree(src_dir, dst_dir, symlinks=True, dirs_exist_ok=True)

Setting symlinks=True recreates the link at the destination pointing to the same target path; if the target lies outside the copied tree, the link remains functional only if the target is accessible from the destination location.

Error‑Resilient Copies

Network or removable media can produce transient I/O errors. Wrapping the copy in a retry loop with exponential backoff makes the operation more dependable:

import time

def resilient_copy(src, dst, retries=3, delay=1):
    for attempt in range(1, retries + 1):
        try:
            shutil.copy2(src, dst)
            return
        except OSError as exc:
            if attempt == retries:
                raise
            time.sleep(delay * attempt)  # back off

Putting It All Together – A Utility Function

Below is a compact utility that combines chunked copying, optional progress reporting, symlink handling, and basic error resilience:

def smart_copy(src, dst, *, chunk_size=1024*1024, show_progress=False,
               preserve_symlinks=False, max_retries=2):
    if os.path.isdir(src):
        shutil.copytree(
            src, dst,
            copy_function=lambda s, d: _chunked_copy(s, d, chunk_size, show_progress),
            symlinks=preserve_symlinks,
            dirs_exist_ok=True
        )
    else:
        _chunked_copy(src, dst, chunk_size, show_progress)

def _chunked_copy(src, dst, chunk_size, show_progress):
    if show_progress:
        total = os.And basename(src)) as pbar:
            with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
                while True:
                    data = fsrc. write(data)
                    pbar.Day to day, path. That said, path. read(chunk_size)
                    if not data:
                        break
                    fdst.On top of that, getsize(src)
        with tqdm(total=total, unit='B', unit_scale=True,
                  desc=os. On the flip side, update(len(data))
    else:
        with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
            while True:
                data = fsrc. read(chunk_size)
                if not data:
                    break
                fdst.

### Conclusion  
Python’s standard library already provides powerful, high‑level primitives for copying

files, yet understanding the underlying mechanics allows you to tailor behavior to specific needs. By leveraging chunked I/O, metadata preservation, symbolic link handling, and retry logic, you can build strong file-copying utilities that perform well across diverse environments—from local filesystems to network-mounted storage. The key is to balance simplicity with control, using built-in functions like `shutil.copy2` and `shutil.copytree` as starting points, then extending them with custom logic when necessary. With careful attention to buffer sizes, progress tracking, and error resilience, even mundane tasks like copying files can be transformed into reliable, efficient operations suitable for production systems.
Fresh Stories

Just Released

These Connect Well

People Also Read

Thank you for reading about Python Copy File From One Directory To Another. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home