Как я могу безопасно создать вложенный каталог в Python?

avatar
Parand
7 ноября 2008 в 18:56
3021010
30
4856

Какой самый элегантный способ проверить, существует ли каталог, в который будет записан файл, и если нет, создать каталог с помощью 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 (спасибо, Канжа, Блер и Дуглас). Вот что у меня сейчас:

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

Есть ли флаг для «открыто», чтобы это происходило автоматически?

Источник
Brian Hawkins
26 мая 2010 в 23:30
36

В общем, вам может потребоваться учитывать случай, когда в имени файла нет каталога. На моей машине dirname ('foo.txt') дает '', которого не существует и вызывает сбой makedirs ().

miracle173
19 февраля 2014 в 19:52
7

если путь существует, нужно не только проверить, является ли он каталогом, а не обычным файлом или другим объектом (многие ответы проверяют это), также необходимо проверить, доступен ли он для записи (я не нашел ответа, который проверял это)

Thamme Gowda
25 октября 2016 в 03:40
10

Если вы пришли сюда, чтобы создать родительские каталоги строки пути к файлу p, вот мой фрагмент кода: os.makedirs(p[:p.rindex(os.path.sep)], exist_ok=True)

Ответы (30)

avatar
Blair Conrad
7 ноября 2008 в 19:06
6081

На 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.exists и os.makedirs, os.makedirs завершится ошибкой с OSError. К сожалению, перехват OSError и продолжение не является надежным, так как он игнорирует сбой при создании каталога из-за других факторов, таких как недостаточные разрешения, полный диск и т. Д.

Один из вариантов - перехватить OSError и изучить встроенный код ошибки (см. Есть ли кроссплатформенный способ получения информации от Python OSError):

import os, errno

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

В качестве альтернативы может быть второй os.path.exists, но предположим, что другой создал каталог после первой проверки, а затем удалил его перед второй - нас все равно можно обмануть.

В зависимости от приложения опасность одновременных операций может быть больше или меньше опасности, исходящей от других факторов, таких как права доступа к файлам. Прежде чем выбирать реализацию, разработчик должен узнать больше о конкретном разрабатываемом приложении и его ожидаемой среде.

Современные версии Python немного улучшают этот код, как за счет раскрытия FileExistsError (в версии 3.3 +) ...

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

... и разрешив аргумент ключевого слова для os.makedirs, вызванного exist_ok (в версии 3.2+).

os.makedirs("path/to/directory", exist_ok=True)  # succeeds even if directory exists.
Blair Conrad
7 ноября 2008 в 20:35
8

Состояние гонки - хороший момент, но подход, описанный в coderhelper.com/questions/273192/#273208, замаскирует ошибку при создании каталога. Не расстраивайтесь из-за того, что проголосовали против - вам не нравится ответ. Это то, за что нужны голоса.

Andrew
28 ноября 2011 в 19:10
31

Помните, что os.path.exists () не бесплатен. Если в нормальном случае каталог будет там, то случай, когда его нет, следует рассматривать как исключение. Другими словами, попробуйте открыть и записать в свой файл, перехватить исключение OSError и, в зависимости от ошибки, выполнить makedir () и повторить попытку или повторно вызвать. Это создает дублирование кода, если вы не переносите запись в локальный метод.

Asclepius
14 февраля 2013 в 17:32
25

os.path.exists также возвращает True для файла. Я отправил ответ на этот вопрос.

Bobble
20 мая 2013 в 06:50
14

Как отмечали здесь комментаторы других ответов, параметр exists_ok для os.makedirs() может использоваться, чтобы указать, как обрабатывается предыдущее существование пути, начиная с Python 3.2.

drevicko
6 июля 2013 в 06:41
7

os.mkdirs() может создавать непредусмотренные папки, если разделитель пути случайно пропущен, текущая папка не такая, как ожидалось, элемент пути содержит разделитель пути. Если вы используете os.mkdir(), эти ошибки вызовут исключение, предупреждающее вас об их существовании.

avatar
simone
14 марта 2022 в 10:12
1

самый быстрый и безопасный способ сделать это: он создаст, если не существует, и пропустит, если существует:

from pathlib import Path
Path("path/with/childs/.../").mkdir(parents=True, exist_ok=True)
avatar
Devil
8 февраля 2022 в 06:11
2

Лучший способ сделать это в Python

#Devil
import os
directory = "./out_dir/subdir1/subdir2"
if not os.path.exists(directory):
    os.makedirs(directory)
avatar
Dominykas Mostauskis
17 августа 2021 в 17:24
7

Если вы пишете файл по переменному пути, вы можете использовать это в пути к файлу, чтобы убедиться, что родительские каталоги созданы.

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_file равно file.ext (нулевая глубина каталогов).

См. pathlib.PurePath.parent и pathlib.Path.mkdir.

avatar
korakot
22 октября 2020 в 03:32
2

Вы можете создать файл и все его родительские каталоги с помощью одной команды с расширением fastcore для pathlib: path.mk_write(data)

from fastcore.utils import Path
Path('/dir/to/file.txt').mk_write('Hello World')
avatar
Sergiy Maksymenko
10 сентября 2020 в 03:39
-1

В Linux вы можете создать каталог в одной строке:

import os
os.system("mkdir -p {0}".format('mydir'))
avatar
Hussam Kurd
19 мая 2019 в 00:32
6

Перед созданием каталога необходимо указать полный путь:

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)

Это работает для меня и, надеюсь, сработает и для вас

avatar
Geoff Paul Bremner
11 сентября 2018 в 18:23
7

Почему бы не использовать модуль подпроцесса, если он запущен на машине, поддерживающей команду mkdir с опцией -p? Работает на python 2.7 и python 3.6

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

Подойдет для большинства систем.

В ситуациях, когда переносимость не имеет значения (например, при использовании докера), решение - чистые 2 строки. Вам также не нужно добавлять логику для проверки, существуют ли каталоги или нет. Наконец, можно безопасно запустить повторно без каких-либо побочных эффектов

Если вам нужна обработка ошибок:

from subprocess import check_call
try:
    check_call(['mkdir', '-p', 'path1/path2/path3'])
except:
    handle...
avatar
Steffi Keran Rani J
28 апреля 2018 в 16:00
5

Вызов функции 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')
avatar
Manivannan Murugavel
16 апреля 2018 в 07:30
7

Используйте эту команду, проверьте и создайте каталог

 if not os.path.isdir(test_img_dir):
     os.mkdir(test_img_dir)
avatar
Victoria Stuart
16 декабря 2017 в 04:16
8

Я нашел этот вопрос / ответ, и сначала был озадачен некоторыми сбоями и ошибками, которые я получал. Я работаю в Python 3 (v.3.5 в виртуальной среде Anaconda в системе Arch Linux x86_64).

Рассмотрим эту структуру каталогов:

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

Вот мои эксперименты / заметки, которые проясняют ситуацию:

# ----------------------------------------------------------------------------
# [1] https://coderhelper.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

avatar
Evil Exists
5 июля 2017 в 23:15
0
import os
if os.path.isfile(filename):
    print "file exists"
else:
    "Your code here"

Там, где находится ваш код, используйте (сенсорную) команду

Это проверит, есть ли файл, если его нет, и создаст его.

avatar
Michael Strobel
9 февраля 2017 в 03:56
8

Я использую os.path.exists(), здесь - это скрипт Python 3, который можно использовать, чтобы проверить, существует ли каталог, создать его, если он не существует, и удалить его, если он существует (при желании ).

Он предлагает пользователям ввести каталог и может быть легко изменен.

avatar
euccas
3 января 2017 в 22:33
16

В Python3 , os.makedirs поддерживает настройку exist_ok. Значение по умолчанию - False, что означает, что OSError будет выдано, если целевой каталог уже существует. Если задать для exist_ok значение True, OSError (каталог существует) будет проигнорирован, и каталог не будет создан.

os.makedirs(path,exist_ok=True)

В Python2 , os.makedirs не поддерживает настройку exist_ok. Вы можете использовать этот подход в ответе Хейкки-Тойвонена:

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST:
            raise
avatar
hiro protagonist
14 декабря 2016 в 16:06
96

Начиная с 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)

Это рекурсивно создает каталог и не вызывает исключения, если каталог уже существует.

(так же, как os.makedirs получил флаг exist_ok, начиная с python 3.2, например, os.makedirs(path, exist_ok=True))


Примечание: когда я опубликовал этот ответ, ни один из других ответов не упоминал exist_ok ...

avatar
Ralph Schwerdt
3 декабря 2016 в 16:00
4

Если учесть следующее:

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

означает, что каталог (путь) существует И это каталог. Так что для меня этот способ делает то, что мне нужно. Поэтому я могу убедиться, что это папка (а не файл) и она существует.

avatar
Dennis Golomazov
13 сентября 2016 в 21:44
10

Вы можете использовать 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.

avatar
iPhynx
8 июня 2016 в 12:52
5

Вы можете использовать os.listdir для этого:

import os
if 'dirName' in os.listdir('parentFolderPath')
    print('Directory Exists')
avatar
tashuhka
29 марта 2016 в 15:50
18

Для однострочного решения вы можете использовать IPython.utils.path.ensure_dir_exists():

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

Из документации : Убедитесь, что каталог существует. Если его не существует, попробуйте создать его и защитить от состояния гонки, если другой процесс делает то же самое.

IPython - это пакет расширения, а не часть стандартной библиотеки.

avatar
alissonmuller
8 февраля 2016 в 04:08
6

Я видел ответы Хейкки Тойвонена и A-B-B и думал об этом варианте.

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
avatar
Antti Haapala
11 марта 2015 в 20:50
22

В 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.
avatar
Aaron Hall
22 января 2015 в 23:49
51

Понимание специфики данной ситуации

Вы указываете конкретный файл по определенному пути и извлекаете каталог из пути к файлу. Затем, убедившись, что у вас есть каталог, вы пытаетесь открыть файл для чтения. Чтобы прокомментировать этот код:

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)
avatar
Aaron Hall
22 января 2015 в 23:45
28

Проверить, существует ли каталог, и при необходимости создать его?

Прямой ответ на этот вопрос заключается в предположении простой ситуации, когда вы не ожидаете, что другие пользователи или процессы будут вмешиваться в ваш каталог:

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.

(Для контекста, я отслеживаю свою еженедельную репутацию с помощью скрипта. Вот соответствующие части кода из скрипта, которые позволяют мне избежать переполнения стека более одного раза в день для одних и тех же данных.)

Сначала соответствующий импорт:

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

Path объекты должны быть приведены к str, прежде чем другие API, ожидающие пути str, смогут их использовать.

Возможно, Pandas следует обновить, чтобы принимать экземпляры абстрактного базового класса, os.PathLike.

avatar
kavadias
14 июля 2014 в 15:29
14

соответствующая документация Python предлагает использовать стиль кодирования EAFP (проще просить прощения, чем разрешения). Это означает, что код

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

Документация предполагает это именно из-за состояния гонки, обсуждаемого в этом вопросе. Вдобавок, как здесь упоминают другие, есть преимущество в производительности при однократном запросе, а не при двукратном запросе ОС. Наконец, аргумент, выдвинутый, возможно, в пользу второго кода в некоторых случаях - когда разработчик знает среду, в которой работает приложение, - может быть поддержан только в том особом случае, когда программа настроила частную среду для сам (и другие экземпляры той же программы).

Даже в этом случае это плохая практика и может привести к долгой бесполезной отладке. Например, тот факт, что мы устанавливаем разрешения для каталога, не должен оставлять нас с разрешениями на показ, установленными в соответствии с нашими целями. Родительский каталог может быть смонтирован с другими разрешениями. В общем, программа всегда должна работать правильно, и программист не должен рассчитывать на одну конкретную среду.

avatar
Asclepius
16 января 2013 в 17:31
1368

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. Backport предлагает более новую и улучшенную реализацию mkdir, которая включает этот отсутствующий параметр.

Использование os:

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

os.makedirs при использовании выше рекурсивно создает каталог и не вызывает исключение, если каталог уже существует. Он имеет необязательный аргумент exist_ok только при использовании Python 3.2+ со значением по умолчанию 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, то есть errno.EEXIST, возникает как для файлов, так и для каталогов. Надежнее просто проверить, существует ли каталог.

Альтернатива:

mkpath создает вложенный каталог и ничего не делает, если каталог уже существует. Это работает как в Python 2, так и в 3.

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

Согласно ошибке 10948, серьезным ограничением этой альтернативы является то, что она работает только один раз на процесс python для заданного пути. Другими словами, если вы используете его для создания каталога, затем удалите каталог изнутри или вне Python, а затем снова воспользуетесь mkpath, чтобы воссоздать тот же каталог, mkpath просто молча использует свою недопустимую кэшированную информацию о ранее созданных каталог и фактически не будет создавать каталог снова. Напротив, os.makedirs не полагается на какой-либо такой кеш. Это ограничение может быть приемлемым для некоторых приложений.


Что касается режима каталога , обратитесь к документации, если вам это интересно.

Charles L.
26 апреля 2013 в 05:52
15

Насколько я могу судить, этот ответ охватывает практически все частные случаи. Я планирую обернуть это в «if not os.path.isdir ()», хотя, поскольку я ожидаю, что каталог будет существовать почти каждый раз, и таким образом я могу избежать исключения.

jpmc26
29 апреля 2014 в 22:39
6

@CharlesL. Исключение, вероятно, дешевле, чем дисковый ввод-вывод проверки, если ваша причина - производительность.

kwarunek
19 сентября 2014 в 10:31
2

@ jpmc26, но makedirs выполняет дополнительные stat, umask, lstat только при проверке на выброс OSError.

penguin359
30 декабря 2015 в 21:54
0

@CharesL В любое время, когда есть разделитель каталогов, os.makedirs () начинается со stat (), поэтому предварительная проверка с помощью os.path.isdir () - это просто дополнительные усилия.

sleepycal
8 января 2016 в 15:20
5

Это неправильный ответ, поскольку он вводит потенциальное условие гонки FS. См. Ответ Аарона Холла.

farmir
27 апреля 2016 в 07:20
6

как сказал @sleepycal, это страдает от того же состояния гонки, что и принятый ответ. Если между появлением ошибки и проверкой os.path.isdir кто-то другой удалит папку, вы вызовете неправильную, устаревшую и сбивающую с толку ошибку, что папка существует.

nealmcb
22 октября 2017 в 16:21
0

Обеспокоенность по поводу условий гонки, отмеченная @sleepycal, рассматривается в комментариях к ответу Хейкки Тойвонена для многих (большинства) случаев использования, включая мой. Если вы беспокоитесь, что кто-то другой собирается удалить каталог, вам все равно нужно будет проверить это, прежде чем использовать его позже. Создание нескольких мест, где вы проверяете, что вам понадобится позже, только добавляет сложности.

smci
8 января 2019 в 09:08
0

В Windows, как насчет ошибок разрешений, когда родительский каталог принадлежит администратору, или же специальный каталог, например C:\Program Files or ...(x86) или Documents and Settings, и, следовательно, создать каталог не удается? Распространяет ли этот код точную ошибку разрешений?

Asclepius
8 января 2019 в 17:13
0

@smci Это не похоже, но, по крайней мере, в Linux можно проверить доступные разрешения. Насчет винды не знаю.

fitzl
9 января 2019 в 06:03
0

Обратите внимание, что NotADirectoryError: [Errno 20] Not a directory: ... - это , возникший с помощью pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True) в тех случаях, когда существует файл, совпадающий с предложенным именем каталога в пути, например, если my является файлом.

avatar
Heikki Toivonen
17 февраля 2011 в 17:17
624

Использование 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

Другими словами, мы пытаемся создать каталоги, но если они уже существуют, мы игнорируем ошибку. С другой стороны, сообщается о любой другой ошибке. Например, если вы заранее создадите каталог 'a' и удалите из него все разрешения, вы получите OSError, сгенерированный с помощью errno.EACCES (Permission denied, error 13).

isaaclw
13 апреля 2012 в 19:46
2

Какая общая причина против этого? то есть: почему люди предпочитают оператор if, а не try / except? Неужели попытка / кроме более опасна, если вы пропустите ошибку?

Heikki Toivonen
7 мая 2012 в 18:23
25

Принятый ответ на самом деле опасен, потому что он имеет состояние гонки. Однако это проще, поэтому, если вы не знаете о состоянии гонки или думаете, что оно не применимо к вам, это будет ваш очевидный первый выбор.

Asclepius
16 января 2013 в 17:13
17

Исключение возникает только тогда, когда exception.errno != errno.EEXIST непреднамеренно игнорирует случай, когда путь существует, но является объектом, не относящимся к каталогу, например файлом. В идеале исключение должно возникать, если путь не относится к объекту каталога.

Navin
9 февраля 2013 в 15:36
187

Обратите внимание, что приведенный выше код эквивалентен os.makedirs(path,exist_ok=True)

Asclepius
14 февраля 2013 в 17:46
59

@Navin Параметр exist_ok был введен в Python 3.2. Его нет в Python 2.x. Я включу это в свой ответ.

jpmc26
29 апреля 2014 в 22:41
27

@HeikkiToivonen С технической точки зрения, если другая программа изменяет каталоги и файлы одновременно с вашей программой, вся ваша программа представляет собой одно гигантское состояние гонки. Что помешает другой программе просто удалить этот каталог после того, как код создаст его, но до того, как вы фактически поместите в него файлы?

gerrit
25 мая 2016 в 14:07
1

В Python 3.3 и выше вы можете использовать FileExistsError.

Clément
31 мая 2017 в 02:41
2

Проголосовали против. Исходный код mkdirs фактически предупреждает против проверки EEXIST: github.com/python/cpython/blob/…

rtkaleta
4 июля 2017 в 13:41
0

@ Clément Вы смотрите исходный код Python 3.x, приведенный выше ответ относится к Python 2.7: github.com/python/cpython/blob/2.7/Lib/os.py#L153

Clément
4 июля 2017 в 14:59
0

@rtkaleta: Это не имеет значения. Возможно, проблема не была исправлена ​​в версии 2.7, но, тем не менее, она существует.

Davis Herring
2 октября 2017 в 23:58
1

@ jpmc26: Дело не в том, что нет условий гонки; дело в том, что ваша программа не содержит двух ​​разных мест, где вы могли бы определить, что (из-за расы) на самом деле является одним и тем же условием.

jpmc26
3 октября 2017 в 00:27
0

@DavisHerring То, что вы говорите, не совсем правда. Проверка существования происходит каждый раз, когда вы обращаетесь к каталогу или его содержимому. Таким образом, если вы создадите каталог, а затем откроете в нем файл, вы все равно будете уязвимы для того же состояния гонки. Ответ хороший; это просто все еще небезопасно, если другая программа что-то модифицирует, как утверждал Хейкки (не ответ).

Davis Herring
3 октября 2017 в 00:47
0

@ jpmc26: С другой стороны, расы материально хуже: с if not path.exists(...) одновременный mkdir может дать вам исключение (несмотря на проверку). В более широком смысле, проверка не защищает вас от необходимости иметь дело с каким-либо состоянием гонки, поэтому ее включение явно хуже.

jpmc26
3 октября 2017 в 00:59
0

@DavisHerring Этот ответ также не мешает вам иметь дело с какими-либо условиями гонки. Если ваша программа конкурирует с другой программой за контроль над каталогом, вы делаете это неправильно .

Davis Herring
3 октября 2017 в 02:03
0

@ jpmc26: предотвращает гонку mkdir (в том смысле, что у вас есть два ясных случая и очевидные пути кода для их решения). Соревнование не обязательно должно быть «битвой»: легко, когда несколько программ создают разные части каталога.

avatar
crimsonstone
14 января 2009 в 17:57
114

Я лично рекомендую вам использовать os.path.isdir() для тестирования вместо 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().

avatar
Ali Afshar
7 ноября 2008 в 21:23
36

Я записал следующее. Однако это не совсем надежно.

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

Теперь, как я уже сказал, это не совсем надежно, потому что у нас есть возможность не создать каталог и другой процесс, создающий его в течение этого периода.

avatar
Douglas Mayle
7 ноября 2008 в 19:01
89

Отметьте os.makedirs: (Проверяет, существует ли полный путь.)
Чтобы справиться с тем фактом, что каталог может существовать, поймайте OSError. (Если exist_ok равно False (по умолчанию), возникает OSError, если целевой каталог уже существует.)

import os
try:
    os.makedirs('./path/to/somewhere')
except OSError:
    pass
Blair Conrad
7 ноября 2008 в 19:09
21

с помощью try / except вы замаскируете ошибки при создании каталога, в случае, когда каталог не существует, но по какой-то причине вы не можете его сделать

avatar
gone
7 ноября 2008 в 19:00
42

Попробуйте os.path.exists функцию

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