如果像
b/c/
这样的路径在 ./a/b/c
中不存在,shutil.copy("./blah.txt", "./a/b/c/blah.txt")
会抱怨目的地不存在。创建目标路径并将文件复制到该路径的最佳方法是什么?
总结给定答案和评论中的信息:
对于Python 3.2+:
os.makedirs
之前 copy
与 exist_ok=True
:
os.makedirs(os.path.dirname(dest_fpath), exist_ok=True)
shutil.copy(src_fpath, dest_fpath)
对于Python < 3.2:
os.makedirs
抓住 IOError
后再次尝试复制:
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)
虽然您可以更明确地检查
errno
和/或在 exists
之前检查路径 makedirs
,但恕我直言,这些片段在简单性和功能性之间取得了很好的平衡。
使用
os.makedirs
创建目录树。
我使用与此类似的方法来检查该目录是否存在,然后再对其进行操作。
if not os.path.exists('a/b/c/'):
os.mkdir('a/b/c')
这是EAFP方式,可以避免竞争和不需要的系统调用:
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 FileNotFoundError: # raised also on missing dest parent dir
# try creating parent directories
os.makedirs(os.path.dirname(dest), exist_ok=True)
shutil.copy(src, dest)
对于 3.4/3.5+,您可以使用 pathlib:
Path.mkdir(mode=0o777,parents=False,exist_ok=False)
因此,如果可能需要创建多个目录并且它们可能已经存在:
pathlib.Path(dst).mkdir(parents=True, exist_ok=True)
我如何使用 split 将目录从路径中取出
dir_name, _ = os.path.split("./a/b/c/blah.txt")
然后
os.makedirs(dir_name,exist_ok=True)
最后
shutil.copy("./blah.txt", "./a/b/c/blah.txt")
我的五美分是下一个方法:
# 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)
许多其他答案都适用于旧版本的 Python,尽管它们可能仍然有效,但您可以使用较新的 Python 更好地处理错误。
如果您使用的是 Python 3.3 或更高版本,我们可以捕获
FileNotFoundError
而不是 IOError
。我们还想区分目标路径不存在和源路径不存在。我们想吞下前一个异常,但不想吞下后者。
最后,请注意
os.makedirs()
一次递归地创建一个缺失的目录——这意味着它不是一个原子操作。如果您有多个线程或进程可能尝试同时创建相同的目录树,您可能会看到意外的行为。
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