如何递归地创建目录?

269

有没有一种Python方法可以递归创建目录?我有这个路径:

/home/dail/

我想创建

/home/dail/first/second/third

我能递归地做吗,还是必须一个接一个地创建目录?

chmodchown 能否递归地执行操作,而无需分别为每个文件/目录分配权限?


3
超集:还要检查是否存在:https://dev59.com/I3RB5IYBdhLWcg3wgXhV中的mkdir-p功能 - Ciro Santilli OurBigBook.com
1
可能是如何安全地创建嵌套目录?的重复问题。 - jww
@Chen 谢谢!很有趣对吧? :-) - Ciro Santilli OurBigBook.com
5个回答

400

从Python 3.2开始,您可以这样做:

import os
path = '/home/dail/first/second/third'
os.makedirs(path, exist_ok=True)

感谢exist_ok标志,如果目录已经存在,则即使根据您的需求也不会发出投诉。


从Python 3.4开始(包括pathlib模块),您可以这样做:

from pathlib import Path
path = Path('/home/dail/first/second/third')
path.mkdir(parents=True)

从Python 3.5开始,mkdir也有一个exist_ok标志 - 将其设置为True如果目录存在,则不会引发异常:

path.mkdir(parents=True, exist_ok=True)

2
感谢您的帮助。我一直在使用os.mkdir,但它无法创建孙子目录和更多嵌套的子目录。os.makedirs解决了我的问题。 - Hamed_gibago
3
@Hamed_gibago,你甚至不需要使用pathlib模块。os.makedirs本身就是递归的... - hiro protagonist
3
不错。pathlib 对我很有用。 - Manthan Patel

257

os.makedirs 是您需要的。对于 chmodchown,您将需要使用 os.walk 并在每个文件/目录上手动执行。


11
具体来说: os.makedirs(os.path.join("/home/dail", "first", "second", "third")) - mseery
19
注意,exist_ok=True这个参数非常方便,可以避免每次都要检查文件是否已经存在。 - ideasman42
29
请注意,在Python 3.2中才添加了exist_ok参数。 - JKillian

15

尝试使用os.makedirs函数:

import os
import errno

try:
    os.makedirs(<path>)
except OSError as e:
    if errno.EEXIST != e.errno:
        raise

4
欢迎来到 Stack Overflow!感谢您提供这段代码片段,它可能会立即提供一些帮助。通过显示为什么这是一个好的解决方案,适当的解释将极大地改善 它的教育价值,并使它对未来读者具有相似但不完全相同问题的人更有用。请[编辑]您的答案以添加解释,并指出适用的限制和假设。 - Toby Speight
1
我认为这个答案适用于Python 2.x,因为它正确地处理错误,并且不会两次要求文件系统的路径(与os.path.exists方法相比)。 - wonder.mice

8
以下是我提供的实现参考代码:
def _mkdir_recursive(self, path):
    sub_path = os.path.dirname(path)
    if not os.path.exists(sub_path):
        self._mkdir_recursive(sub_path)
    if not os.path.exists(path):
        os.mkdir(path)

希望这能有所帮助!

4
如果第一个文件夹不存在,这个函数将导致堆栈溢出(如果不是 os.path.exists(sub_path) 语句始终为 true 并调用自身)。但只要第一个目录存在,这个函数似乎可以正常工作。 - Ronen Ness
1
首先检查第一个文件夹是否存在,问题就可以简单地解决。 - user14803978

7

我同意Cat Plus Plus的答案。然而,如果你知道这个程序只会在类Unix操作系统上使用,你可以使用外部调用shell命令mkdirchmodchown。确保传递额外的标志以递归影响目录:

>>> import subprocess
>>> subprocess.check_output(['mkdir', '-p', 'first/second/third']) 
# Equivalent to running 'mkdir -p first/second/third' in a shell (which creates
# parent directories if they do not yet exist).

>>> subprocess.check_output(['chown', '-R', 'dail:users', 'first'])
# Recursively change owner to 'dail' and group to 'users' for 'first' and all of
# its subdirectories.

>>> subprocess.check_output(['chmod', '-R', 'g+w', 'first'])
# Add group write permissions to 'first' and all of its subdirectories.

编辑:我最初使用了commands,这是一个糟糕的选择,因为它已经被弃用,并且容易受到注入攻击的影响。例如,如果用户输入来创建一个名为first/;rm -rf --no-preserve-root /;的文件夹,则有可能删除所有目录。

编辑2:如果你正在使用Python 2.7以下版本,请使用check_call代替check_output。详见subprocess文档


4
但那不是Python,那是一个shell脚本!如果你能用Python编写一个简单甚至是可移植的解决方案,就用Python吧。 ;) - Rosh Oxymoron
1
@Rosh:我完全同意Python调用*nix shell命令并不具备可移植性(我也这么说过)。但是,我经常发现自己编写快速Python脚本,只在自己的Linux机器上使用。对于这些目的,调用shell命令可能更简单,当您可以通过标志(例如-R而不是walk双重循环-(每个walked dir中的文件的第二个循环))实现所需内容时。当然,我本可以用bash编写它们,但我觉得Python的语法很方便(易于定义函数/类),并且对所有命令行标志都有访问权限,这对我很方便。 - dr jimbob
@dothebart 我同意分叉通常是个坏主意,会有更多的开销。但差别只有几毫秒(所以除非你正在创建数千个目录或在一个非常资源紧张的系统上——然后你可能需要重新考虑使用Python)。有时候,一个熟悉的Shell命令,在一行中做到你想要的事情比使用Python的命令复制功能更方便(例如,Python的os.chmodos.chown没有递归选项)。说分叉总是不好似乎是一种过早的优化。 - dr jimbob
请查看pyrrd模块和Rethink。现在提出的解决方案值得更多关注 - 这就是为什么我投了赞成票,而这个投了反对票。 - dothebart
Python的subprocess模块可以安全地使用(不需要shell=True),当您已经熟悉用于完成任务的shell命令,并且这是您不介意使用shell脚本完成的任务时,它非常有用(即在这里,您不会为每个命令优化几毫秒的差异)。 我真的不在乎你是否对此进行了负评(现在它被锁定了),尽管我不同意这是一个"明显而且可能危险错误的答案",应该被投票下降。 - dr jimbob
显示剩余2条评论

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