Copy A File In Python
October - 2021
The basic way to copy a file in Python 3 is (though it does not do all metadata)
from shutil import copy2
source_path = 'some/source/path.txt'
dest_path = 'path/to/put/the/file.txt'
copy2(source_path, dest_path)
- It will copy files and directories (need to test the last part)
- It also copies file permissions.
- Via: https://stackoverflow.com/questions/123198/how-do-i-copy-a-file-in-python
Here's a nice table someone put together:
| Function | Copies Metadata | Copies Permissions | Can Specify Buffer |
|-------------|-----------------|--------------------|--------------------|
| copy | No | Yes | No |
| copyfile | No | No | No |
| copy2 | Yes | Yes | No |
| copyfileobj | No | No | Yes |
Old Notes:
See this from here: https://alexwlchan.net/2019/03/atomic-cross-filesystem-moves-in-python/
import errno
import os
import shutil
def safe_move(src, dst):
"""Rename a file from ``src`` to ``dst``.
* Moves must be atomic. ``shutil.move()`` is not atomic.
Note that multiple threads may try to write to the cache at once,
so atomicity is required to ensure the serving on one thread doesn't
pick up a partially saved image from another thread.
* Moves must work across filesystems. Often temp directories and the
cache directories live on different filesystems. ``os.rename()`` can
throw errors if run across filesystems.
So we try ``os.rename()``, but if we detect a cross-filesystem copy, we
switch to ``shutil.move()`` with some wrappers to make it atomic.
"""
try:
os.rename(src, dst)
except OSError as err:
if err.errno == errno.EXDEV:
# Generate a unique ID, and copy `<src>` to the target directory
# with a temporary name `<dst>.<ID>.tmp`. Because we're copying
# across a filesystem boundary, this initial copy may not be
# atomic. We intersperse a random UUID so if different processes
# are copying into `<dst>`, they don't overlap in their tmp copies.
copy_id = uuid.uuid4()
tmp_dst = "%s.%s.tmp" % (dst, copy_id)
shutil.copyfile(src, tmp_dst)
# Then do an atomic rename onto the new name, and clean up the
# source image.
os.rename(tmp_dst, dst)
os.unlink(src)
else:
raise