Fundamentals 12 min read

9 Powerful Python Techniques to Copy Files Efficiently

Learn nine distinct Python approaches for copying files—including shutil functions, os commands, threading, and subprocess methods—while understanding their performance implications, error handling, platform compatibility, and when to choose each technique for optimal I/O efficiency.

Raymond Ops
Raymond Ops
Raymond Ops
9 Powerful Python Techniques to Copy Files Efficiently

Python provides many built‑in modules (such as

os

,

subprocess

and

shutil

) to support file I/O operations. Choosing the most suitable file‑copy method is important because file I/O is performance‑intensive and can become a bottleneck. Different scenarios may require blocking, asynchronous, or platform‑specific approaches.

shutil

copyfile()

method

shutil

copy()

method

shutil

copyfileobj()

method

shutil

copy2()

method

os

popen()

method

os

system()

method

threading

Thread()

method

subprocess

call()

method

subprocess

check_output()

method

shutil copyfile() method

This method copies the source file to the destination only when the target is writable; otherwise it raises an

IOError

. It opens the source for reading, ignores file type, and does not preserve special files. Internally it uses the low‑level

copyfileobj()

function, optionally accepting a buffer size.

<code>copyfile(source_file, destination_file)</code>

Key points:

Copies source content to the destination file.

Raises

IOError

if the destination is not writable.

Raises

SameFileError

when source and destination are the same.

Overwrites existing files with a different name.

Fails with

Error 13

if the destination is a directory.

Does not support copying character or block devices, pipes, etc.

shutil copy() method

Similar to the Unix

cp

command. If the destination is a directory, a new file with the same base name is created inside it. After copying the data, the method also synchronises the destination file’s permissions with the source.

<code>copy(source_file, [destination_file or dest_dir])</code>

Differences from

copyfile()

:

copy()

can set permission bits while

copyfile()

only copies data.

If the destination is a directory,

copy()

succeeds;

copyfile()

fails with

Error 13

.

copy()

internally calls

copyfile()

and

copymode()

.

shutil copyfileobj() method

Copies the contents of a file object to another file object. An optional buffer size (default 16 KB) can be supplied to control the amount of data read into memory per block.

<code>from shutil import copyfileobj
status = False
if isinstance(target, string_types):
    target = open(target, 'wb')
    status = True
try:
    copyfileobj(self.stream, target, buffer_size)
finally:
    if status:
        target.close()
</code>

shutil copy2() method

Works like

copy()

but also copies metadata such as access and modification times. It raises

SameFileError

when source and destination refer to the same file.

Differences from

copy()

:

copy2()

preserves timestamps in addition to permissions.

Internally it calls

copystat()

instead of

copymode()

.

os popen() method

Creates a pipe to or from a command. Returns a file object connected to the pipe, which can be used for reading or writing (default mode is

r

).

<code>os.popen(command[, mode[, bufsize]])</code>

Parameters:

mode

:

r

(read) or

w

(write).

bufsize

: 0 (unbuffered), 1 (line buffered), >1 (buffered with given size), or negative (system default).

os system() method

Executes a system command in a subshell and returns the command’s exit status. It is a simple way to run external commands.

<code>os.system('copy 1.txt.py 2.txt.py')  # Windows example
os.system('cp 1.txt.py 2.txt.py')    # Linux example</code>

Thread‑based file copy (asynchronous)

Uses the

threading

module to perform a copy operation in the background. Ensure proper locking when multiple threads access files to avoid deadlocks.

<code>import shutil
from threading import Thread
src = "1.txt.py"
dst = "3.txt.py"
Thread(target=shutil.copy, args=[src, dst]).start()
</code>

subprocess call() method

Runs a command in a subprocess, waits for it to complete, and returns the exit code. It replaces older functions like

os.system

,

os.spawn

, and

os.popen

.

<code>import subprocess
src = "1.txt.py"
dst = "2.txt.py"
cmd = 'copy "%s" "%s"' % (src, dst)
status = subprocess.call(cmd, shell=True)
if status != 0:
    print("Command failed with return code", status)
else:
    print("Execution of %s passed!" % cmd)
</code>

subprocess check_output() method

Runs a command and captures its output. Useful when the result of the command is needed for further processing.

<code>import os, subprocess
src = os.path.realpath(os.getcwd() + "http://cdn.techbeamers.com/1.txt.py")
dst = os.path.realpath(os.getcwd() + "http://cdn.techbeamers.com/2.txt.py")
cmd = 'copy "%s" "%s"' % (src, dst)
status = subprocess.check_output(['copy', src, dst], shell=True)
print("status:", status.decode('utf-8'))
</code>

These nine methods cover a range of use‑cases—from simple, high‑level copies with

shutil

to low‑level system commands and asynchronous threading—allowing developers to select the most appropriate technique based on performance, portability, and error‑handling requirements.

PythonFile I/Othreadingshutilsubprocesscopyfile
Raymond Ops
Written by

Raymond Ops

Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.