繁体   English   中英

Python 中的 mkdir -p 功能 [重复]

[英]mkdir -p functionality in Python [duplicate]

有没有办法从 Python 中在 shell 上获得类似于mkdir -p功能。 我正在寻找系统调用以外的解决方案。 代码肯定不到20行,不知道有没有人写过?

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

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

在 Python 3.5 中添加了exist_ok参数。


对于 Python ≥ 3.2, os.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

在 Python >=3.2 中,就是

os.makedirs(path, exist_ok=True)

在早期版本中,使用@tzot 的回答

这比捕获异常更容易:

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']

如果文件已经存在, mkdir -p会给你一个错误:

$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory `/tmp/foo': File exists

因此,如果os.path.isdir返回False (检查errno.EEXIST ),则对先前建议的改进是重新raise异常。

(更新)另见这个高度相似的问题 我同意接受的答案(和警告),但我会推荐os.path.isdir而不是os.path.exists

(更新)根据评论中的建议,完整功能如下:

import os
def mkdirp(directory):
    if not os.path.isdir(directory):
        os.makedirs(directory) 

使用 python3 标准库中的Pathlib

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

如果父母为真,则根据需要创建此路径的任何缺失父母; 它们是使用默认权限创建的,不考虑模式(模仿 POSIX mkdir -p 命令)。 如果exist_ok 为false(默认值),如果目标目录已经存在,则会引发FileExistsError。

如果exist_ok 为true,FileExistsError 异常将被忽略(与POSIX mkdir -p 命令的行为相同),但前提是最后一个路径组件不是现有的非目录文件。

在 3.5 版更改:添加了exist_ok 参数。

正如其他解决方案中提到的,我们希望能够在模仿mkdir -p行为的同时访问文件系统一次。 我不认为这是可能的,但我们应该尽可能接近。

先上代码,后解释:

import os
import errno

def mkdir_p(path):
    """ 'mkdir -p' in Python """
    try:
        os.makedirs(path)
    except OSError as exc:  # Python >2.5
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise

由于对@tzot 的回答的评论表明在实际创建目录之前检查您是否可以创建目录存在问题:您无法判断是否有人在此期间更改了文件系统。 这也符合 Python 请求宽恕而不是许可的风格。

所以我们应该做的第一件事就是尝试制作目录,然后如果出错,找出原因。

正如 Jacob Gabrielson 指出的那样,我们必须寻找的一种情况是我们试图放置目录的文件已经存在的情况。

使用mkdir -p

$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory '/tmp/foo': File exists

Python 中的类似行为是引发异常。

所以我们必须弄清楚是否是这种情况。 不幸的是,我们不能。 无论目录存在(好)还是文件存在阻止创建目录(坏),我们都会从 makedirs 得到相同的错误消息。

确定发生了什么的唯一方法是再次检查文件系统以查看那里是否有目录。 如果有,则静默返回,否则引发异常。

唯一的问题是文件系统现在可能处于与调用 makedirs 时不同的状态。 例如:一个文件存在导致 makedirs 失败,但现在一个目录在它的位置。 这并不重要,因为该函数只会在最后一次文件系统调用时该目录存在时静默退出而不会引发异常。

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

import os

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

或者

import os
import errno

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

这些都处理路径已经静默存在但让其他错误冒泡的情况。

函数声明;

import os
def mkdir_p(filename):

    try:
        folder=os.path.dirname(filename)  
        if not os.path.exists(folder):  
            os.makedirs(folder)
        return True
    except:
        return False

用法 :

filename = "./download/80c16ee665c8/upload/backup/mysql/2014-12-22/adclient_sql_2014-12-22-13-38.sql.gz"

if (mkdir_p(filename):
    print "Created dir :%s" % (os.path.dirname(filename))
import os
import tempfile

path = tempfile.mktemp(dir=path)
os.makedirs(path)
os.rmdir(path)

我个人在以下方面取得了成功,但我的函数可能应该被称为“确保此目录存在”之类的东西:

def mkdirRecursive(dirpath):
    import os
    if os.path.isdir(dirpath): return

    h,t = os.path.split(dirpath) # head/tail
    if not os.path.isdir(h):
        mkdirRecursive(h)

    os.mkdir(join(h,t))
# end mkdirRecursive
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 的回答,但修复了部分树已经存在的错误

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM