5105

检查要写入文件的目录是否存在,如果不存在,使用 Python 创建目录的最优雅方法是什么?这是我尝试过的:

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)

是否有一个标志open(),可以自动发生这种情况?

4

29 回答 29

6415

在 Python ≥ 3.5 上,使用pathlib.Path.mkdir

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

对于旧版本的 Python,我看到两个质量很好的答案,每个都有一个小缺陷,所以我会给出我的看法:

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

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

正如评论和其他地方所指出的,存在竞争条件——如果目录是在os.path.existsos.makedirs调用之间创建的,os.makedirs则将失败并带有OSError. 不幸的是,一揽子捕获OSError和继续并不是万无一失的,因为它会忽略由于其他因素导致的目录创建失败,例如权限不足、磁盘已满等。

一种选择是捕获OSError并检查嵌入的错误代码(请参阅Is there a cross-platform way of getting information from Python's OSError):

import os, errno

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

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

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

FileExistsError现代版本的 Python 通过暴露(在 3.3+ 中)对这段代码进行了相当多的改进......

try:
    os.makedirs("path/to/directory")
except FileExistsError:
    # directory already exists
    pass

...并通过允许调用关键字参数os.makedirsexist_ok(在 3.2+ 中)。

os.makedirs("path/to/directory", exist_ok=True)  # succeeds even if directory exists.
于 2008-11-07T19:06:07.663 回答
1428

Python 3.5+:

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

pathlib.Path.mkdir如上所述,递归地创建目录,如果目录已经存在,则不会引发异常。如果您不需要或不希望创建父母,请跳过该parents参数。

Python 3.2+:

使用pathlib

如果可以,请安装pathlib名为pathlib2. 不要安装名为pathlib. 接下来,参考上面的 Python 3.5+ 部分,同样使用它。

如果使用 Python 3.4,即使它带有pathlib,它也缺少有用的exist_ok选项。向后移植旨在提供一种更新和更好的实现,mkdir其中包括这个缺失的选项。

使用os

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

os.makedirs如上所述,递归地创建目录,如果目录已经存在,则不会引发异常。仅当使用 Python 3.2+ 时它才具有可选exist_ok参数,默认值为False. 此参数在 Python 2.x 到 2.7 中不存在。因此,不需要像 Python 2.7 那样手动处理异常。

Python 2.7+:

使用pathlib

如果可以,请安装pathlib名为pathlib2. 不要安装名为pathlib. 接下来,参考上面的 Python 3.5+ 部分,同样使用它。

使用os

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

虽然一个简单的解决方案可能首先使用os.path.isdir后跟os.makedirs,但上面的解决方案颠倒了这两个操作的顺序。这样做,它可以防止与创建目录的重复尝试有关的常见竞争条件,并且还可以消除目录中的文件歧义。

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

选择:

mkpath创建嵌套目录,如果目录已经存在,则不执行任何操作。这适用于 Python 2 和 3。

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

根据Bug 10948,此替代方案的一个严重限制是它对于给定路径的每个 python 进程仅工作一次。换句话说,如果你使用它来创建一个目录,然后从 Python 内部或外部删除该目录,然后mkpath再次使用它来重新创建相同的目录,mkpath将只是默默地使用其先前创建目录的无效缓存信息,并且不会实际上再次制作目录。相反,os.makedirs不依赖任何此类缓存。对于某些应用程序,此限制可能没问题。


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

于 2013-01-16T17:31:19.700 回答
643

使用 try except 和来自 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

换句话说,我们尝试创建目录,但如果它们已经存在,我们将忽略错误。另一方面,报告任何其他错误。例如,如果您事先创建 dir 'a' 并从中删除所有权限,您将收到一个OSError引发errno.EACCES(Permission denied, error 13)。

于 2011-02-17T17:17:25.517 回答
123

从 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)

这会递归地创建目录,如果目录已经存在,则不会引发异常。

(就像从 python 3.2 开始os.makedirs的标志一样)exist_okos.makedirs(path, exist_ok=True)


注意:当我发布这个答案时,没有提到其他答案exist_ok......

于 2016-12-14T16:06:09.100 回答
122

我个人建议您使用os.path.isdir()to test 而不是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(":: ")

还有一个愚蠢的用户输入:

:: /tmp/dirname/filename.etc

...filename.etc如果os.makedirs()您使用os.path.exists().

于 2009-01-14T17:57:32.920 回答
97

检查os.makedirs:(确保完整路径存在。)
要处理目录可能存在的事实,请 catch OSError。(如果exist_okFalse(默认值),OSError如果目标目录已经存在,则会引发 an。)

import os
try:
    os.makedirs('./path/to/somewhere')
except OSError:
    pass
于 2008-11-07T19:01:25.677 回答
63

试试这个os.path.exists功能

if not os.path.exists(dir):
    os.mkdir(dir)
于 2008-11-07T19:00:01.717 回答
57

关于这种情况的具体情况的见解

您在特定路径中提供特定文件,然后从文件路径中提取目录。然后在确保您拥有该目录之后,您尝试打开一个文件进行读取。要评论此代码:

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)

假设开放阅读

你为什么要为一个你希望在那里并且能够读取的文件创建一个目录?

只需尝试打开文件。

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

如果目录或文件不存在,您将获得一个IOError带有相关错误号的:errno.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附加)。使用上下文管理器打开文件也是 Python 的最佳实践。

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

但是,假设我们有几个 Python 进程试图将它们的所有数据放到同一个目录中。然后我们可能会争用目录的创建。在这种情况下,最好将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)
于 2015-01-22T23:49:18.630 回答
41

我已经把以下内容。不过,这也不是万无一失的。

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

现在正如我所说,这并不是万无一失的,因为我们有可能无法创建目录,并且在此期间有另一个进程创建它。

于 2008-11-07T21:23:03.333 回答
33

检查目录是否存在并在必要时创建它?

对此的直接答案是,假设您不希望其他用户或进程弄乱您的目录的简单情况:

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

或者,如果使目录受制于竞争条件(即,如果在检查路径存在之后,可能已经有其他东西),请执行以下操作:

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 中的新功能:pathlib.Path使用exist_ok

有一个新Path对象(从 3.4 开始)有很多方法可以用于路径 - 其中之一是mkdir.

(对于上下文,我正在使用脚本跟踪我的每周代表。以下是脚本中代码的相关部分,可以让我避免每天针对相同的数据多次访问 Stack Overflow。)

首先是相关的进口:

from pathlib import Path
import tempfile

我们现在不必处理os.path.join- 只需将路径部分加入/

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

然后我幂等地确保目录存在 -exist_ok参数显示在 Python 3.5 中:

directory.mkdir(exist_ok=True)

这是文档的相关部分:

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

这是脚本的更多内容 - 就我而言,我不受竞争条件的影响,我只有一个进程希望目录(或包含的文件)在那里,并且我没有任何尝试删除的内容目录。

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))

Pathstr在其他期望str路径的 API 可以使用它们之前,必须强制对象。

也许应该更新 Pandas 以接受抽象基类的实例,os.PathLike.

于 2015-01-22T23:45:59.470 回答
26

在 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.
于 2015-03-11T20:50:01.437 回答
25

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

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

文档中:确保目录存在。如果它不存在,请尝试创建它并在另一个进程正在执行相同操作时防止出现竞争条件。

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

于 2016-03-29T15:50:53.783 回答
21

Python3中,os.makedirs支持设置exist_ok。默认设置是False,这意味着OSError如果目标目录已经存在,将引发 an 。通过设置exist_okTrue, 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
于 2017-01-03T22:33:47.480 回答
19

相关的Python 文档建议使用EAFP 编码风格(Easier to Ask for Forgiveness than Permission)。这意味着代码

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

文档表明这一点正是因为这个问题中讨论的竞争条件。此外,正如其他人在这里提到的那样,查询一次而不是两次操作系统具有性能优势。最后,在某些情况下(当开发人员知道应用程序正在运行的环境时)提出的论点可能支持第二个代码,只能在程序设置了私有环境的特殊情况下被提倡。本身(以及同一程序的其他实例)。

即使在这种情况下,这也是一种不好的做法,并且可能导致长时间无用的调试。例如,我们为目录设置权限这一事实不应该给我们留下印象权限是为我们的目的而适当设置的。可以使用其他权限安装父目录。一般来说,一个程序应该总是正确地工作,程序员不应该期望一个特定的环境。

于 2014-07-14T15:29:07.270 回答
16

在我对在 Python 中使用目录时遇到的一些失败和错误感到困惑之后,我发现了这个 Q/A。我正在使用 Python 3(Arch Linux x86_64 系统上的 Anaconda 虚拟环境中的 v.3.5)。

考虑这个目录结构:

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

这是我的实验/笔记,提供了说明:

# ----------------------------------------------------------------------------
# [1] https://stackoverflow.com/questions/273192/how-can-i-create-a-directory-if-it-does-not-exist

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

于 2017-12-16T04:16:07.307 回答
14

您可以使用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。

于 2016-09-13T21:44:56.923 回答
11

我使用os.path.exists(),是一个 Python 3 脚本,可用于检查目录是否存在,如果不存在则创建一个,如果存在则删除它(如果需要)。

它提示用户输入目录并且可以很容易地修改。

于 2017-02-09T03:56:05.167 回答
11

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

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

应该在大多数系统上做到这一点。

在可移植性无关紧要的情况下(例如,使用 docker),解决方案是干净的 2 行。您也不必添加逻辑来检查目录是否存在。最后,重新运行是安全的,没有任何副作用

如果您需要错误处理:

from subprocess import check_call
try:
    check_call(['mkdir', '-p', 'path1/path2/path3'])
except:
    handle...
于 2018-09-11T18:23:57.367 回答
11

您必须在创建目录之前设置完整路径:

import os,sys,inspect
import pathlib

currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
your_folder = currentdir + "/" + "your_folder"

if not os.path.exists(your_folder):
   pathlib.Path(your_folder).mkdir(parents=True, exist_ok=True)

这对我有用,希望它也对你有用

于 2019-05-19T00:32:23.273 回答
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

于 2021-08-17T17:24:05.227 回答
10

我看到Heikki ToivonenABB的回答并想到了这种变化。

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
于 2016-02-08T04:08:06.240 回答
10

使用此命令检查并创建目录

 if not os.path.isdir(test_img_dir):
     os.mkdir(test_img_dir)
于 2018-04-16T07:30:10.890 回答
9

create_dir()在程序/项目的入口点调用该函数。

import os

def create_dir(directory):
    if not os.path.exists(directory):
        print('Creating Directory '+directory)
        os.makedirs(directory)

create_dir('Project directory')
于 2018-04-28T16:00:40.573 回答
8

您可以os.listdir为此使用:

import os
if 'dirName' in os.listdir('parentFolderPath')
    print('Directory Exists')
于 2016-06-08T12:52:46.870 回答
7

如果您考虑以下情况:

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

表示存在目录(路径)并且是目录。所以对我来说,这种方式可以满足我的需要。所以我可以确保它是文件夹(不是文件)并且存在。

于 2016-12-03T16:00:13.347 回答
4

这可能不能完全回答这个问题。但我猜你的真正意图是创建一个文件及其父目录,因为它的内容全部在 1 个命令中。

您可以通过fastcore对 pathlib 的扩展来做到这一点:path.mk_write(data)

from fastcore.utils import Path
Path('/dir/to/file.txt').mk_write('Hello World')

在fastcore 文档中查看更多信息

于 2020-10-22T03:32:43.977 回答
2
import os
if os.path.isfile(filename):
    print "file exists"
else:
    "Your code here"

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

这将检查文件是否存在,如果不存在,它将创建它。

于 2017-07-05T23:15:27.847 回答
1

在 python 中执行此操作的最佳方法

#Devil
import os
directory = "./out_dir/subdir1/subdir2"
if not os.path.exists(directory):
    os.makedirs(directory)
于 2022-02-08T06:11:08.027 回答
-3

在 Linux 下你可以创建嵌套目录

 dir1/dir2/... 

在一行中:

import os
os.system("mkdir -p {0}".format('dir1/dir2/dir3'))
于 2020-09-10T03:39:26.787 回答