How to Copy a File in Python

Introduction

When it comes to using Python to copy files, there are two main ways: using the shutil module or the os module. All of the os methods we show here are methods that allow us to execute shell commands from our Python code, which we'll use to execute the copy command (Windows) or the cp command (Unix).

You'll notice that many of these methods, in both the shutil module and the os module, have very similar functionality (which shouldn't be surprising), but each varies in functionality from each other very slightly, which I'll explain as well.

Copying Files with the shutil Module

The shutil module offers several high level methods to copy files. Here below are the main ones:

copyfile

This method copies the content of one file into another file. The destination provided to it must be a writable file, and have a different name than the source file. If the names are the same then it will generate an error. If the destination file already exists, it will be replaced with the newly copied file.

The syntax for this method is:

shutil.copyfile(src_file, dest_file, *, follow_symlinks=True)  

For example, the following code will copy a file named "file1.txt" into a file named "file2.txt":

import shutil

shutil.copyfile('file1.txt', 'file2.txt')  

One interesting and potentially useful feature of shutil.copyfile is the follow_symlinks Boolean argument. If it is set to False, and the source file is a symbolic link, then instead of copying the file, a new symbolic link will be created.

copy

This method is very similar to copyfile, with the main difference being that in addition to copying the content of the source file, it goes one step further and also copies the file's file system permissions. Copying file permissions is not a trivial task in most programming languages, so this is a nice feature to have.

The syntax is as follows:

shutil.copy(src_file, dest_file, *, follow_symlinks=True)  

Each of these parameters are the same as in the copyfile method. For example, the following code will copy "file1.txt" into "file3.txt".

import shutil

shutil.copy('file1.txt', 'file3.txt')  

Note: Make sure you don't name your script the same as one of the module you're importing (which I mistakenly did when testing code for this article). If you do, then you'll get an error when trying to import that module due to a circular import problem.

copy2

As with the previous methods, copy2 method is identical to the copy method, but in addition to copying the file contents it also attempts to preserve all the source file's metadata. If the platform doesn't allow for full metadata saving, then copy2 doesn't return failure and it will just preserve any metadata it can.

The syntax is as follows:

shutil.copy2(src_file, dest_file, *, follow_symlinks=True)  

Again, these parameters are the same as in the previous commands we've mentioned so far.

For example, the following code will copy "file1.txt" into "file4.txt", as well as preserve the metadata of the original file, "file1.txt".

import shutil

shutil.copy2('file1.txt', 'file4.txt')  
$ python copy-files.py 
$ ls -l
total 32  
-rw-r--r--  1 scott  staff  91 Oct 27 11:26 copy-files.py
-rw-r--r--  1 scott  staff   6 Oct 27 11:27 file1.txt
-rw-r--r--  1 scott  staff   6 Oct 27 11:29 file3.txt
-rw-r--r--  1 scott  staff   6 Oct 27 11:27 file4.txt

As we can see from executing our code above, "file1.txt" was copied to "file4.txt". However, you may have noticed the creation date was preserved on the new file, unlike with shutil.copy, which copied "file1.txt" to "file3.txt" and gave it a new creation date.

copyfileobj

This method copies the content of a source file into a destination file, from the current source-file position. What this means is that if you read data from your source file object, then the position you stop reading at is the position copyfileobj starts copying from.

The syntax is as follows:

shutil.copyfileobj(src_file_object, dest_file_object[, length])  

The meanings of source and destination file parameters are similar to the previous commands, but now, they refer to objects. The length parameter is optional and represents the buffer size that is the number of bites kept in memory during the copy process. This option can be useful when copying very large files, as it can speed up the copying process and avoids uncontrolled memory usage.

For example the following code will copy "file1.txt" into "file5.txt"

import shutil

filename1 = 'file1.txt'  
fileA = open(filename1, 'rb')

filename2 = 'file5.txt'  
fileB = open(filename2, 'wb')

shutil.copyfileobj(fileA, fileB)  

As we can see, in order to use copyfileobj, we need to open the files in binary mode (which is the "b" part of "rb" and "wb"). In addition, the source file must be opened as readable and the destination file must be opened as writable (the "r" and "w" parts, respectively).

Copying Files with the os Module

The os module provides a way to use the operating system functionality to copy your files. In most (if not all) of the examples from here on out we provide examples that work for both Windows and Unix. The examples are different because of the shell commands used, so be sure to pay attention to how each function call is labeled in the Python comments.

popen

This method opens a pipe to or from your command. However, note that this method was deprecated in Python 2.6, so we don't recommend using it unless you have to. As an alternative, the Python documentation advises us to use methods from the subprocess module instead.

The syntax is as follows:

os.popen(cmd[, mode[, bufsize]])  

Here the value returned is a file object that is connected to the pipe. This object can be read from or written to depending on the mode. The default mode is 'r', which allows reading of the file contents.

The example below will copy "file1.txt" into "file6.txt":

import os

# Windows
os.popen('copy file1.txt file6.txt')

# Unix
os.popen('cp file1.txt file6.txt')  

Running the command in this way is exactly the same as if you ran it directly from the command line of your terminal.

system

This method executes the specified command in a subshell. It is available for both Unix and Windows. The syntax is as follows:

os.system(command)  

Here command is a string containing the DOS or Unix shell command. In our case, this is where we'll put the copy or cp command.

For example, the following code will copy "file1.txt" into "file7.txt"

import os

# Windows
os.system('copy file1.txt file7.txt')

# Unix
os.system('cp file1.txt file7.txt')  

This looks identical to the previous os.popen command we just used, but the command is executed in a subshell, which means it is executed in a separate thread in parallel to your executing code. To wait for its completion, you need to call .wait() on the object returned by os.system.

Copying Files with the subprocess Module

The subprocess module intends to replace some methods in the os module (particularly os.system and the os.spawn* methods), and it presents two main methods to access the operating system commands. These methods are call and check_output. Once again, for Unix systems, the command "copy file1.txt file2.txt" should be replaced by "cp file1.txt file2.txt".

call Method

The Python documentation recommends us to use the call method to launch a command from the operating system.

The syntax is as follows:

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)  

The args parameter will include our shell command. However, a word of caution, as the Python documentation warns us that using shell=True can be a security risk.

Using this function call, we can run our copy command as follows:

import subprocess

# Windows
status = subprocess.call('copy file1.txt file8.txt', shell=True)

# Unix
status = subprocess.call('cp file1.txt file8.txt', shell=True)  

As the example above shows, we simply need to pass a string with the shell command, as before.

And as expected, the operating system will copy "file1.txt" into a file named "file8.txt".

check_output Method

This method also allows us to execute a command within a shell. It is very much like the subprocess.run command, except that by default it pipes data from stdout as encoded bytes. The syntax is as follows:

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)  

Here the args parameter includes the shell command we want to use. Once again, the Python documentation warns us of using shell=True, so use this method with caution.

In the following code we'll copy "file1.txt" to "file9.txt" using the check_output command:

import subprocess

# Windows
status = subprocess.check_output('copy file1.txt file9.txt', shell=True)

# Unix
status = subprocess.check_output('cp file1.txt file9.txt', shell=True)  

And as with all of the commands we've shown in this article, this will copy the file "file1.txt" to the destination we specified, which is "file9.txt" here.

Wrapping Up

Python offers us many different ways to copy files, some of which are part of the Python set of methods. Others use some of Python's powerfull methods to execute commands in a shell, which utilize shell commands like copy or cp.

Not sure which one is right for you? We presented a lot of different ways to copy files here, so that's understandable. The method you use to copy a file is completely up to you and will depend on your specific needs. Although in most cases one of the shutil commands will work just fine for you. Try starting with shutil.copy2 and see if that does what you need.

Which method do you use and why? Let us know in the comments!