是否有一种方法可以从Python内部获得类似于shell上的mkdir -p的功能。我正在寻找一个解决方案,而不是系统调用。我确信代码少于20行,我想知道是否有人已经写了它?


当前回答

这比捕获异常更容易:

import os
if not os.path.exists(...):
    os.makedirs(...)

这种方法需要两次系统调用,在某些环境/条件下更容易受到竞争条件的影响。如果您正在编写比在受控环境中运行的简单的一次性脚本更复杂的东西,那么您最好使用只需要一次系统调用的可接受答案。

更新2012-07-27

我很想删除这个答案,但我认为下面的评论有价值。因此,我将其转换为wiki。

其他回答

最近,我发现这个distutils.dir_util.mkpath:

In [17]: from distutils.dir_util import mkpath

In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']

我认为Asa的回答基本上是正确的,但你也可以将其扩展一点,使其更像mkdir -p:

import os

def mkdir_path(path):
    if not os.access(path, os.F_OK):
        os.mkdirs(path)

or

import os
import errno

def mkdir_path(path):
    try:
        os.mkdirs(path)
    except os.error, e:
        if e.errno != errno.EEXIST:
            raise

这两种方法都可以处理路径已经静默存在但会出现其他错误的情况。

对于Python≥3.5,使用pathlib.Path.mkdir:

import pathlib
pathlib.Path("/tmp/path/to/desired/directory").mkdir(parents=True, exist_ok=True)

exist_ok形参在Python 3.5中添加。


适用于Python≥3.2版本。makedirs有一个可选的第三个参数exist_ok,当它为True时,启用mkdir -p功能——除非提供了mode,并且现有目录的权限与预期的权限不同;在这种情况下,OSError会像之前一样被引发:

import os
os.makedirs("/tmp/path/to/desired/directory", exist_ok=True)

对于更老版本的Python,您可以使用os。Makedirs并忽略错误:

import errno    
import os

def mkdir_p(path):
    try:
        os.makedirs(path)
    except OSError as exc:  # Python ≥ 2.5
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        # possibly handle other errno cases here, otherwise finally:
        else:
            raise

使用python3标准库中的Pathlib:

Path(mypath).mkdir(parents=True, exist_ok=True)

If parents is true, any missing parents of this path are created as needed; they are created with the default permissions without taking mode into account (mimicking the POSIX mkdir -p command). If exist_ok is false (the default), an FileExistsError is raised if the target directory already exists. If exist_ok is true, FileExistsError exceptions will be ignored (same behavior as the POSIX mkdir -p command), but only if the last path component is not an existing non-directory file. Changed in version 3.5: The exist_ok parameter was added.

import os
from os.path import join as join_paths

def mk_dir_recursive(dir_path):

    if os.path.isdir(dir_path):
        return
    h, t = os.path.split(dir_path)  # head/tail
    if not os.path.isdir(h):
        mk_dir_recursive(h)

    new_path = join_paths(h, t)
    if not os.path.isdir(new_path):
        os.mkdir(new_path)

基于@Dave C的回答,但修复了部分树已经存在的错误