Copy file with pathlib in Python

To use shutil.copy:

import pathlib
import shutil

my_file = pathlib.Path('/etc/hosts')
to_file = pathlib.Path('/tmp/foo')

shutil.copy(str(my_file), str(to_file))  # For Python <= 3.7.
shutil.copy(my_file, to_file)  # For Python 3.8+.

The problem is pathlib.Path create a PosixPath object if you're using Unix/Linux, WindowsPath if you're using Microsoft Windows.

With older versions of Python, shutil.copy requires a string as its arguments. For them, use the str function here.


Since Python 3.5, without importing shutil, you can do:

from pathlib import Path

dest = Path('dest')
src = Path('src')
dest.write_bytes(src.read_bytes()) #for binary files
dest.write_text(src.read_text()) #for text files

For Python 2.7, pathlib2 provides the read_bytes, read_text, write_bytes and write_text methods.

The file will be loaded in memory, so this method is not suitable for files larger than the machines available memory.

As per the comments, one can use write_bytes and read_bytes to copy text files, but if you need to deal with the encoding at copy time write_text an read_text present the advantage of two extra parameters:

  • encoding is the name of the encoding used to decode or encode the file
  • errors is an optional string that specifies how encoding and decoding errors are to be handled

They both have the same meaning as in open().


The cause for shutil.copy() not working is that you are not using the latest Python, Python 3.6 shutil.copy() can handle Path objects (or subclasses thereof). That for older versions of Python this throws an error is because those implementations of shutil expect string arguments for copy, and not pathlib.Path type arguments.

What you actually want to be able to write is:

my_file.copy(to_file)

You can subclass Path to include such a method, and adapt the creation of my_file. I find it easier to just graft/monkey-patch/duck-punch it on the existing pathlib.Path

from pathlib import Path


def _copy(self, target):
    import shutil
    assert self.is_file()
    shutil.copy(str(self), str(target))  # str() only there for Python < (3, 6)

Path.copy = _copy

You can put this code anywhere you like, as long as it gets executed before calling the .copy method on any of the Path instances. The argument to .copy() can be a file or a directory.