create destination path for shutil.copy files

Python

Python Problem Overview


If a path such as b/c/ does not exist in ./a/b/c , shutil.copy("./blah.txt", "./a/b/c/blah.txt") will complain that the destination does not exist. What is the best way to create both the destination path and copy the file to this path?

Python Solutions


Solution 1 - Python

To summarize info from the given answers and comments:

For python 3.2+:

os.makedirs before copy with exist_ok=True:

os.makedirs(os.path.dirname(dest_fpath), exist_ok=True)
shutil.copy(src_fpath, dest_fpath)

For python < 3.2:

os.makedirs after catching the IOError and try copying again:

try:
    shutil.copy(src_fpath, dest_fpath)
except IOError as io_err:
    os.makedirs(os.path.dirname(dest_fpath))
    shutil.copy(src_fpath, dest_fpath)

Although you could be more explicit about checking errno and/or checking if path exists before makedirs, IMHO these snippets strike a nice balance between simplicity and functionality.

Solution 2 - Python

Use os.makedirs to create the directory tree.

Solution 3 - Python

I use something similar to this to check if the directory exists before doing things with it.

if not os.path.exists('a/b/c/'):
    os.mkdir('a/b/c')

Solution 4 - Python

This is the EAFP way, which avoids races and unneeded syscalls:

import errno
import os
import shutil

src = "./blah.txt"
dest = "./a/b/c/blah.txt"
# with open(src, 'w'): pass # create the src file
try:
    shutil.copy(src, dest)
except IOError as e:
    # ENOENT(2): file does not exist, raised also on missing dest parent dir
    if e.errno != errno.ENOENT:
        raise
    # try creating parent directories
    os.makedirs(os.path.dirname(dest))
    shutil.copy(src, dest)

Solution 5 - Python

For 3.4/3.5+ you can use pathlib:

> Path.mkdir(mode=0o777, parents=False, exist_ok=False)


So if there might be multiple directories to create and if they might already exist:

pathlib.Path(dst).mkdir(parents=True, exist_ok=True)

Solution 6 - Python

How about I use split to get the dir out of the path

dir_name, _ = os.path.split("./a/b/c/blah.txt")

then

os.makedirs(dir_name,exist_ok=True)

and finally

shutil.copy("./blah.txt", "./a/b/c/blah.txt")

Solution 7 - Python

My five cents there would be is the next approach:

# Absolute destination path.
dst_path = '/a/b/c/blah.txt'
origin_path = './blah.txt'
not os.path.exists(dst_path) or os.makedirs(dst_path)
shutil.copy(origin_path, dst_path)

Solution 8 - Python

A lot of the other answers are for older versions of Python, although they may still work, you can handle errors a lot better with newer Pythons.

If you are using Python 3.3 or newer, we can catch FileNotFoundError instead of IOError. We also want to differentiate between the destination path not existing and the source path not existing. We want to swallow the former exception, but not the latter.

Finally, beware that os.makedirs() recursively creates missing directories one at a time--meaning that it is not an atomic operation. You may witness unexpected behavior if you have multiple threads or processes that might try to create the same directory tree at the same time.

def copy_path(*, src, dst, dir_mode=0o777, follow_symlinks: bool = True):
    """
    Copy a source filesystem path to a destination path, creating parent
    directories if they don't exist.

    Args:
        src: The source filesystem path to copy. This must exist on the
            filesystem.

        dst: The destination to copy to. If the parent directories for this
            path do not exist, we will create them.

        dir_mode: The Unix permissions to set for any newly created
            directories.

        follow_symlinks: Whether to follow symlinks during the copy.

    Returns:
        Returns the destination path.
    """
    try:
        return shutil.copy2(src=src, dst=dst, follow_symlinks=follow_symlinks)
    except FileNotFoundError as exc:
        if exc.filename == dst and exc.filename2 is None:
            parent = os.path.dirname(dst)
            os.makedirs(name=parent, mode=dir_mode, exist_ok=True)
            return shutil.copy2(
                src=src,
                dst=dst,
                follow_symlinks=follow_symlinks,
            )
        raise

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjamesView Question on Stackoverflow
Solution 1 - Python7yl4rView Answer on Stackoverflow
Solution 2 - PythonPhilippView Answer on Stackoverflow
Solution 3 - PythonthegrinnerView Answer on Stackoverflow
Solution 4 - PythonMr_and_Mrs_DView Answer on Stackoverflow
Solution 5 - PythonjohnsonView Answer on Stackoverflow
Solution 6 - PythonpeterbView Answer on Stackoverflow
Solution 7 - PythonAndriy IvaneykoView Answer on Stackoverflow
Solution 8 - PythonJames MishraView Answer on Stackoverflow