如何创build一个不存在的目录?

什么是最优雅的方式来检查文件将被写入目录是否存在,如果不是,使用Python创build目录? 这是我试过的:

import os file_path = "/my/directory/filename.txt" directory = os.path.dirname(file_path) try: os.stat(directory) except: os.mkdir(directory) f = file(filename) 

不知何故,我错过了os.path.exists (感谢kanja,Blair和Douglas)。 这是我现在所拥有的:

 def ensure_dir(file_path): directory = os.path.dirname(file_path) if not os.path.exists(directory): os.makedirs(directory) 

有没有“打开”的标志,这使得这自动发生?

我看到两个质量好的答案,每个答案都有一个小小的缺陷,所以我会把这个答案给我:

尝试os.path.exists ,并考虑创buildos.makedirs

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

正如注释和其他地方所指出的那样,竞争条件 – 如果在os.path.existsos.makedirs调用之间创build目录,则os.makedirs将失败,并带有OSError 。 不幸的是,全面捕捉OSError并继续是不是万无一失的,因为它会忽略由于其他因素,如权限不足,完整的磁盘等因素,创build目录失败。

一个select是捕获OSError并检查embedded的错误代码(请参阅从Python的OSError获取信息是否有跨平台的方式 ):

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

或者,可能会有第二个os.path.exists ,但假设另一个在第一次检查之后创build目录,然后在第二个之前删除它 – 我们仍然可能被愚弄。

根据应用程序的不同,并发操作的危险可能比其他因素(如文件权限)带来的危险更大或更小。 在select实现之前,开发人员必须更多地了解正在开发的特定应用程序及其预期的环境。

使用除errno模块以外的错误代码和正确的错误代码来摆脱竞争条件并且是跨平台的:

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

换句话说,我们尝试创build目录,但是如果它们已经存在,我们会忽略这个错误。 另一方面,报告任何其他错误。 例如,如果事先创builddir“a”并从中删除所有权限,则会得到一个由errno.EACCES (Permission denied,error 13)引发的OSError

Python 3.5+:

信用: 由hiro主angular回答

 import pathlib pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True) 

这个recursion的创build目录,如果目录已经存在,不会引发exception。

Python 3.2+:

 import os os.makedirs(path, exist_ok=True) 

如果使用Python 3.2+,则可选的exist_ok参数可用,默认值为False 。 它在Python 2.x中不存在,最高为2.7。 因此可以简单地在Python 3.2+中指定exist_ok=True来避免在目录已经存在的情况下引发exception。 因此,与Python 2.7一样,不需要手动exception处理。

Python 2.7+:

 import os try: os.makedirs(path) except OSError: if not os.path.isdir(path): raise 

虽然一个天真的解决scheme可能首先使用os.path.isdir然后是os.makedirs ,但是上面的解决scheme颠倒了这两个操作的顺序。 这样做可以防止共同的竞争条件与创build目录的重复尝试有关,也可以消除目录中的文件歧义。

请注意,捕获exception并使用errno的用处有限,因为OSError: [Errno 17] File exists ,即errno.EEXIST ,对于文件和目录都会引发。 简单地检查目录是否存在更为可靠。

替代scheme:

根据丹尼斯的回答 ,以下内容也适用。 mkpath创build嵌套目录,如果目录已经存在, mkpath执行任何操作。 这也适用于Python 3。

 import distutils.dir_util distutils.dir_util.mkpath(path) 

根据每个Bug 10948 ,上述技术的一个严重的限制是对于给定的path,它只对每个python进程有效。 换句话说,如果你使用它来创build一个目录,然后从Python内部或外部删除目录,然后再次使用mkpath重新创build相同的目录, mkpath将简单地静静地使用先前创build目录的无效caching信息,实际上不会再次创build目录。 相反, os.makedirs不依赖于任何这样的caching。 对于某些应用程序,这种限制可能没问题。


关于目录的模式 ,如果你关心的话,请参考文档。

我个人build议您使用os.path.isdir()来testing,而不是os.path.exists()

 >>> os.path.exists('/tmp/dirname') True >>> os.path.exists('/tmp/dirname/filename.etc') True >>> os.path.isdir('/tmp/dirname/filename.etc') False >>> os.path.isdir('/tmp/fakedirname') False 

如果你有:

 >>> dir = raw_input(":: ") 

而一个愚蠢的用户input:

 :: /tmp/dirname/filename.etc 

…如果使用os.path.exists()testing, os.path.exists()当您将该parameter passing给os.makedirs()时,您将最终得到一个名为filename.etc的目录。

检查os.makedirs :(它确保完整的path存在。)为了处理该目录可能存在的事实,赶上OSError。

 import os try: os.makedirs('./path/to/somewhere') except OSError: pass 

洞悉这种情况的具体情况

您在特定的path下给出一个特定的文件,然后从文件path中取出目录。 然后确定你有目录后,你试图打开一个文件进行阅读。 对此代码发表评论:

 filename = "/my/directory/filename.txt" dir = os.path.dirname(filename) 

我们要避免覆盖内置函数, dir 。 此外,文件filepath或可能fullfilepath可能是一个比filename更好的语义名称,所以这将是更好的书面:

 import os filepath = '/my/directory/filename.txt' directory = os.path.dirname(filepath) 

你的最终目标是打开这个文件,你最初说,写作,但你基本上是接近这个目标(基于你的代码)这样​​,打开文件阅读

 if not os.path.exists(directory): os.makedirs(directory) f = file(filename) 

假设开放阅读

你为什么要为你想要的文件创build一个目录并且能够读取?

试图打开文件。

 with open(filepath) as my_file: do_stuff(my_file) 

如果目录或文件不存在,您将得到一个带有关联错误编号的IOErrorerrno.ENOENT将指向正确的错误编号,而不考虑您的平台。 你可以抓住它,如果你想,例如:

 import errno try: with open(filepath) as my_file: do_stuff(my_file) except IOError as error: if error.errno == errno.ENOENT: print 'ignoring error because directory or file is not there' else: raise 

假设我们正在写作

可能是你想要的。

在这种情况下,我们可能没有面对任何竞争条件。 所以就像你一样,但是请注意,为了写作,你需要打开与w模式(或a附加)。 使用上下文pipe理器打开文件也是Python的最佳实践。

 import os if not os.path.exists(directory): os.makedirs(directory) with open(filepath, 'w') as my_file: do_stuff(my_file) 

但是,假设我们有几个Python进程试图把他们所有的数据放到同一个目录中。 那么我们可能会争夺目录的创build。 在这种情况下,最好将makedirs呼叫包装在try-except块中。

 import os import errno if not os.path.exists(directory): try: os.makedirs(directory) except OSError as error: if error.errno != errno.EEXIST: raise with open(filepath, 'w') as my_file: do_stuff(my_file) 

我已经放下了。 这不是完全万无一失。

 import os dirname = 'create/me' try: os.makedirs(dirname) except OSError: if os.path.exists(dirname): # We are nearly safe pass else: # There was an error on creation, so make sure we know about it raise 

正如我所说,这不是真正的万无一失,因为我们有可能无法创build目录,另一个过程在那个时期创build它。

从Python 3.5开始, pathlib.Path.mkdir有一个exist_ok标志:

 from pathlib import Path path = Path('/my/directory/filename.txt') path.parent.mkdir(parents=True, exist_ok=True) # path.parent ~ os.path.dirname(path) 

这个recursion的创build目录,如果目录已经存在,不会引发exception。

试试os.path.exists函数

 if not os.path.exists(dir): os.mkdir(dir) 

在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. 

检查一个目录是否存在,并在必要时创build它?

直接的答案是,假设一个简单的情况,你不希望其他用户或进程搞乱你的目录:

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

或者如果使目录受到竞争条件的影响(即如果在检查path存在之后,其他的东西可能已经做到了)做到这一点:

 import errno try: os.makedirs(d) except OSError as exception: if exception.errno != errno.EEXIST: raise 

但也许更好的方法是通过tempfile使用临时目录来回避资源争用问题:

 import tempfile d = tempfile.mkdtemp() 

以下是在线文档中的要点:

 mkdtemp(suffix='', prefix='tmp', dir=None) User-callable function to create and return a unique temporary directory. The return value is the pathname of the directory. The directory is readable, writable, and searchable only by the creating user. Caller is responsible for deleting the directory when done with it. 

Python 3.5中的新增内容:使用exist_ok

有一个新的Path对象(从3.4开始),有许多方法可以用于path – 其中之一是mkdir

(关于上下文,我正在使用一个脚本来跟踪我的每周代表,下面是脚本中的代码的相关部分,这些代码可以避免每天一次针对相同的数据触发Stack Overflow。)

首先相关import:

 from pathlib import Path import tempfile 

我们现在不需要处理os.path.join – 只需要用/连接path部分:

 directory = Path(tempfile.gettempdir()) / 'sodata' 

然后我确定目录是存在的 – exist_ok参数在Python 3.5中显示:

 directory.mkdir(exist_ok=True) 

这里是文档的相关部分:

如果exist_ok为true,则FileExistsErrorexception将被忽略(与POSIX mkdir -p命令行为相同),但exist_ok是最后一个path组件不是现有的非目录文件。

这里是更多的脚本 – 在我的情况下,我不受竞争条件,我只有一个进程,期望目录(或包含的文件)在那里,我没有任何东西试图删除该目录。

 todays_file = directory / str(datetime.datetime.utcnow().date()) if todays_file.exists(): logger.info("todays_file exists: " + str(todays_file)) df = pd.read_json(str(todays_file)) 

在其他需要strpath的API可以使用它们之前, Path对象必须被强制str

也许pandas应该被更新为接受抽象基类os.PathLike

相关的python文档build议使用EAFP编码风格(比容许更容易要求宽恕) 。 这意味着代码

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

比替代scheme更好

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

文档build议这正是由于在这个线程讨论的竞争条件。 另外,正如其他人提到的那样,在查询一次而不是两次操作系统时,性能优势就更大了。 最后,在一些情况下,当开发人员知道应用程序正在运行的环境时,可能会支持第二个代码,这种情况只能在特殊情况下提倡:程序设置了私有环境本身(和同一程序的其他实例)。

即使在这种情况下,这也是一个不好的做法,会导致长时间无用的debugging。 例如,我们为目录设置权限的事实不应该让我们为我们的目的适当地设置印象权限。 父目录可以使用其他权限进行挂载。 一般而言,程序应该始终正常工作,程序员不应该期待一个特定的环境。

你可以使用mkpath

 # Create a directory and any missing ancestor directories. # If the directory already exists, do nothing. from distutils.dir_util import mkpath mkpath("test") 

请注意,它也会创build祖先目录。

它适用于Python 2和3。

我看到了Heikki Toivonen和ABB对这个变化的回答和想法。 你怎么看?

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

对于IPython.utils.path.ensure_dir_exists()解决scheme,您可以使用IPython.utils.path.ensure_dir_exists()

 from IPython.utils.path import ensure_dir_exists ensure_dir_exists(dir) 

从文档 : 确保存在一个目录。 如果它不存在,尝试创build它,并防止竞争条件,如果另一个进程是相同的。

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

 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 

我使用os.path.exists() , 这里是一个python3脚本,可以用来检查一个目录是否存在,创build一个如果不存在,并删除它(如果需要)。 它提示用户input目录,并可以很容易地修改

你可以使用这个os.listdir

 import os if 'dirName' in os.listdir('parentFolderPath') print('Directory Exists') 

使用文件I / O时,需要考虑的重要一点是

TOCTTOU(到使用时间的检查时间)

。 因此,如果稍后进行检查,然后再读取或写入,可能会以未处理的IOexception结束。 最好的办法是。

 try: os.makedirs(dir_path) except OSError as e: if e.errno == errno.EEXIS: pass else: raise 
 import os os.system("mkdir -p ./testdir") 

-p为你做了所有的工作,为什么当linux和windows的powershell拥有mkdir -p多年的时候,进入所有这些尝试/捕获的东西。 单独进行检查的唯一原因是如果您要将信息打印到日志或屏幕上。

如果你考虑以下几点:

 os.path.isdir('/tmp/dirname') 

意味着一个目录(path)存在AND是一个目录。 所以对我来说,这就是我所需要的。 所以我可以确保它是文件夹(不是文件)并存在。

 import os if os.path.isfile(filename): print "file exists" else: "Your code here" 

在这里你的代码使用(touch)命令

这将检查文件是否存在,如果不是,那么它会创build它。

 import os if not os.path.isfile("test") and not os.path.isdir("test"): os.mkdir("test")