我该如何创建一个目录,并创建任何缺失的父级目录?

5602
如何在给定的路径下创建目录,并创建该路径上任何缺失的父目录?例如,Bash 命令 mkdir -p /path/to/nested/directory 可以实现此功能。

41
一般情况下,你可能需要考虑文件名中不存在目录的情况。在我的机器上,dirname('foo.txt')返回'',表示该目录不存在,会导致makedirs()函数失败。请注意不改变原意,使翻译更加通俗易懂。 - Brian Hawkins
9
如果路径存在,不仅需要检查它是否是一个目录而不是一个普通文件或其他对象(许多答案都会检查这一点),还需要检查它是否可写(我没有找到检查这个的答案)。 - miracle173
14
如果您想创建文件路径字符串 p 的父目录,这是我的代码片段:os.makedirs(p[:p.rindex(os.path.sep)], exist_ok=True) - Thamme Gowda
在 Windows 10 中,如果我在文件浏览器中显示目录,则使用 Python(使用3.7.4版本)创建该目录,即使指定exist_ok=True也会返回“文件已存在”的错误。但是,当我关闭文件浏览器并重新运行Python程序时,程序可以正常运行。 - Bruce
29个回答

33

最快、最安全的方法是:如果不存在则创建,如果存在则跳过:

from pathlib import Path
Path("path/with/childs/.../").mkdir(parents=True, exist_ok=True)

31
import os
directory = "./out_dir/subdir1/subdir2"
if not os.path.exists(directory):
    os.makedirs(directory)

27

在 Python 3.4 中,您还可以使用全新的 pathlib 模块:

from pathlib import Path
path = Path("/my/directory/filename.txt")
try:
    if not path.parent.exists():
        path.parent.mkdir(parents=True)
except OSError:
    # handle error; you can also catch specific errors like
    # FileExistsError and so on.

26

对于一行解决方案,您可以使用IPython.utils.path.ensure_dir_exists()

from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)
文档中得知:确保目录存在。如果目录不存在,则尝试创建它,并防止另一个进程同时执行时的竞争条件。

IPython是一个扩展包,不是标准库的一部分。


26
在Python3中,os.makedirs支持设置exist_ok。默认设置为False,这意味着如果目标目录已经存在,将会引发OSError。通过将exist_ok设置为True,将忽略OSError(目录已存在),并且不会创建该目录。
os.makedirs(path,exist_ok=True)

Python2中,os.makedirs不支持设置exist_ok。您可以使用heikki-toivonen的答案中的方法:

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST:
            raise

21

相关Python文档建议使用EAFP编码风格(宁愿请求原谅,而不是征得许可)。这意味着代码

try:
    os.makedirs(path)
except OSError as exception:
    if exception.errno != errno.EEXIST:
        raise
    else:
        print "\nBE CAREFUL! Directory %s already exists." % path

比起替代方案更好

if not os.path.exists(path):
    os.makedirs(path)
else:
    print "\nBE CAREFUL! Directory %s already exists." % path

文档建议这样做,正是因为本问题中讨论的竞态条件。此外,正如其他人在这里提到的,一次查询操作比两次操作系统更具性能优势。最后,可能支持第二个代码的论点——当开发人员知道应用程序运行的环境时——只能在程序为自身(和同一程序的其他实例)设置了私有环境的特殊情况下提倡。即使在这种情况下,这也是一种不好的实践,可能导致长时间无用的调试。例如,我们为目录设置权限的事实不应让我们认为权限已经适当地设置了。父目录可能会以其他权限挂载。通常,程序应始终正确工作,并且程序员不应期望一个特定的环境。

14

在使用Python处理目录时,我遇到了一些失败和错误,让我感到困惑。我正在Anaconda虚拟环境中使用Python 3(v3.5),在Arch Linux x86_64系统上工作。

考虑以下目录结构:

└── output/         ## dir
   ├── corpus       ## file
   ├── corpus2/     ## dir
   └── subdir/      ## dir

这里是我的实验/笔记,它们提供了澄清:

# ----------------------------------------------------------------------------
# [1] https://dev59.com/L3VC5IYBdhLWcg3wfxU8

import pathlib

""" Notes:
        1.  Include a trailing slash at the end of the directory path
            ("Method 1," below).
        2.  If a subdirectory in your intended path matches an existing file
            with same name, you will get the following error:
            "NotADirectoryError: [Errno 20] Not a directory:" ...
"""
# Uncomment and try each of these "out_dir" paths, singly:

# ----------------------------------------------------------------------------
# METHOD 1:
# Re-running does not overwrite existing directories and files; no errors.

# out_dir = 'output/corpus3'                ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/'               ## works
# out_dir = 'output/corpus3/doc1'           ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/doc1/'          ## works
# out_dir = 'output/corpus3/doc1/doc.txt'   ## no error but no file created (os.makedirs creates dir, not files!  ;-)
# out_dir = 'output/corpus2/tfidf/'         ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/'         ## works
# out_dir = 'output/corpus3/a/b/c/d/'       ## works

# [2] https://docs.python.org/3/library/os.html#os.makedirs

# Uncomment these to run "Method 1":

#directory = os.path.dirname(out_dir)
#os.makedirs(directory, mode=0o777, exist_ok=True)

# ----------------------------------------------------------------------------
# METHOD 2:
# Re-running does not overwrite existing directories and files; no errors.

# out_dir = 'output/corpus3'                ## works
# out_dir = 'output/corpus3/'               ## works
# out_dir = 'output/corpus3/doc1'           ## works
# out_dir = 'output/corpus3/doc1/'          ## works
# out_dir = 'output/corpus3/doc1/doc.txt'   ## no error but creates a .../doc.txt./ dir
# out_dir = 'output/corpus2/tfidf/'         ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/'         ## works
# out_dir = 'output/corpus3/a/b/c/d/'       ## works

# Uncomment these to run "Method 2":

#import os, errno
#try:
#       os.makedirs(out_dir)
#except OSError as e:
#       if e.errno != errno.EEXIST:
#               raise
# ----------------------------------------------------------------------------

结论:在我看来,“方法2”更加稳健。

[1] 如何安全地创建嵌套目录?

[2] https://docs.python.org/3/library/os.html#os.makedirs


你的方法一之所以不起作用是因为调用了os.dirname。如果不调用它,方法1就会按预期工作。 - Sören

13
您可以使用 mkpath
# Create a directory and any missing ancestor directories. 
# If the directory already exists, do nothing.

from distutils.dir_util import mkpath
mkpath("test")    

注意它也会创建祖先目录。

它适用于Python 2和3。


11

如果您正在将文件写入变量路径,则可以在文件路径上使用此选项,以确保创建父目录。

from pathlib import Path

path_to_file = Path("zero/or/more/directories/file.ext")
parent_directory_of_file = path_to_file.parent
parent_directory_of_file.mkdir(parents=True, exist_ok=True)

即使 path_to_filefile.ext(零个目录深度),也可以正常工作。

请参见pathlib.PurePath.parentpathlib.Path.mkdir


10

如果在支持带有 -p 选项的命令 mkdir 的机器上运行,则为什么不使用子进程模块?适用于 Python 2.7 和 Python 3.6。

from subprocess import call
call(['mkdir', '-p', 'path1/path2/path3'])

在大多数系统上,这个应该就可以解决问题了。

在不需要可移植性的情况下(例如使用docker),解决方案只需两行代码,无需添加检查目录是否存在的逻辑。最后,重新运行也是安全的,没有任何副作用。

如果您需要错误处理:

from subprocess import check_call
try:
    check_call(['mkdir', '-p', 'path1/path2/path3'])
except:
    handle...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接