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 fileerrors
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.