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

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

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

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

Brian Hawkins 27.05.2010 03:30

В python 2.7 os.path.mkdir не существует. Это os.mkdir.

drevicko 06.07.2013 10:15

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

miracle173 19.02.2014 23:52

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

Thamme Gowda 25.10.2016 06:40

Что касается условий гонки для случая, когда диск почти заполнен, вы можете при желании проверить наличие минимального (определяемого пользователем) порога свободного места, прежде чем пытаться сделать это: Межплатформенное пространство, оставшееся на томе с использованием Python

smci 08.01.2019 12:10
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4 646
6
2 876 639
27
Перейти к ответу Данный вопрос помечен как решенный

Ответы 27

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

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

Я собирался прокомментировать вопрос, но имеется ли в виду os.mkdir? У моего python (2.5.2) нет os.path.mkdir ....

Blair Conrad 07.11.2008 22:01

Метод os.path.mkdir() отсутствует. Модуль os.path реализует несколько полезных функции на именах путей.

Serge S. 21.05.2012 19:14

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

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

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

Blair Conrad 07.11.2008 22:09
OSError будет поднят здесь, если путь - это существующий файл или каталог. Я отправил ответ на этот вопрос.
Acumenus 16.01.2013 21:33

Это на полпути. Вам необходимо проверить состояние дополнительной ошибки OSError, прежде чем принимать решение игнорировать ее. См. stackoverflow.com/a/5032238/763269.

Chris Johnson 15.10.2015 00:31
Ответ принят как подходящий

На 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.

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

Blair Conrad 07.11.2008 23:35

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

Andrew 28.11.2011 23:10
os.path.exists также возвращает True для файла. Я отправил ответ на этот вопрос.
Acumenus 14.02.2013 21:32

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

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

Возможно, будет полезно добавить к этому ответу функции pathlib.Path::is_dir и pathlib.Path::mkdir. Модуль pathlib, временно добавленный к стандартной библиотеке в версии 3.4, обеспечивает объектно-ориентированный, системно-независимый подход к обработке путей. Это включает обработку разделителей пути (через перегрузку /). Пакет доступен для установки через pip и в более ранние версии.

Chris Krycho 04.11.2014 04:28

Жаль, что он отмечен как правильный и получил 1000 голосов. Вы можете и должны поймать errno.EEXIST

Purrell 27.02.2015 03:48

вы можете проверить, возвращает ли os.path.exists значение false после сбоя os.makedirs, и если путь не существует, ясно, что он не был создан тем временем, поэтому это проблема с привилегиями

Vegstar 30.08.2019 18:58

Напомним, что если exist_ok истинно, исключения FileExistsError будут игнорироваться (такое же поведение, как у команды POSIX mkdir -p), но только если последний компонент пути не является существующим файлом, не являющимся каталогом.

Yagiz Degirmenci 07.08.2020 19:34

здесь этот путь упоминается как полный путь к моему каталогу? как использовать мое текущее местоположение автоматически?

Alex 22.02.2021 06:56

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

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

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

stackoverflow.com/questions/273698/…
Ali Afshar 08.11.2008 00:33

Две проблемы: (1) вам необходимо проверить состояние под-ошибки OSError, прежде чем принимать решение о проверке os.path.exists - см. Stackoverflow.com/a/5032238/763269, и (2) успех на os.path.exists не означает, что каталог существует, просто путь существует - это может быть файл, символическая ссылка или другой объект файловой системы.

Chris Johnson 26.06.2018 00:23

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

Если вы используете только isdir, не возникнет ли у вас проблема, когда вы попытаетесь создать каталог, а файл с таким именем уже существует?

MrWonderful 19.02.2014 00:07

@MrWonderful. Результирующее исключение при создании каталога поверх существующего файла будет правильно отражать проблему обратно для вызывающей стороны.

Damian Yerrick 25.07.2015 18:35

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

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

isaaclw 13.04.2012 23:46

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

Heikki Toivonen 07.05.2012 22:23

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

Acumenus 16.01.2013 21:13

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

Navin 09.02.2013 19:36

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

Acumenus 14.02.2013 21:46

@Navin, A-B-B: похоже, что последние сборки 2.x игнорируют ошибку EEXIST, по сути, так же, как в приведенном выше коде. Проверял в 2.7.4.

Josh Segall 08.04.2013 07:37

Неважно, это только для промежуточных путей. Листовой каталог по-прежнему будет вызывать исключение в 2.7.

Josh Segall 08.04.2013 08:22

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

jpmc26 30.04.2014 02:41

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

Acumenus 24.02.2015 19:44

@ A-B-B Владение будет работать только в том случае, если вам не нужны разные экземпляры приложения, читающие одни и те же файлы, и в этом случае вы можете избежать состояния гонки без него, просто осознавая, к чему вы получаете доступ. То же самое и с разрешениями. Есть ли атомарный способ создания каталога и получения блокировки? Если нет, то это не поможет в конкретном случае, представленном здесь. Если да, то это решение не включает его, что означает, что оно так же «опасно», как и другие.

jpmc26 24.02.2015 21:45

рассмотрите возможность использования isdir вместо exists - зависит от сценария использования

A. Binzxxxxxx 13.07.2015 18:52

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

gerrit 25.05.2016 17:07

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

Clément 31.05.2017 05:41

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

rtkaleta 04.07.2017 16:41

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

Clément 04.07.2017 17:59

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

Davis Herring 03.10.2017 02:58

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

jpmc26 03.10.2017 03:27

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

Davis Herring 03.10.2017 03:47

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

jpmc26 03.10.2017 03:59

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

Davis Herring 03.10.2017 05:03

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 не полагается на такой кеш. Это ограничение может быть приемлемым для некоторых приложений.


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

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

Charles L. 26.04.2013 09:52

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

jpmc26 30.04.2014 02:39

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

kwarunek 19.09.2014 14:31

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

penguin359 31.12.2015 00:54

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

sleepycal 08.01.2016 18:20

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

farmir 27.04.2016 10:20

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

nealmcb 22.10.2017 19:21

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

smci 08.01.2019 12:08

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

Acumenus 08.01.2019 20:13

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

fitzl 09.01.2019 09:03

соответствующая документация 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

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

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

Check if a directory exists and create it if necessary?

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

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)

Вот соответствующая часть документация:

If exist_ok is true, FileExistsError exceptions will be ignored (same behavior as the POSIX mkdir -p command), but only if the last path component is not an existing non-directory file.

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

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.

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

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

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)

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

@JanuszSkonieczny pypi.python.org/pypi/pathlib2 - это новый бэкпорт. Старший не обслуживается.

Acumenus 06.12.2017 20:58

Как указано в первой строке ридми; P. Но старый backport все еще действителен для ответа здесь. И это не головная боль именования. Не нужно объяснять, почему и когда использовать pathlib и где pathlib2 для новых пользователей, и я думаю, что профессионалы здесь поймут устаревание;)

Janusz Skonieczny 11.12.2017 18:43

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

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

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

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

Новая документация IPython доступна здесь.

jkdev 05.10.2016 06:33

Наличие модуля IPython не гарантируется. Он изначально присутствует на моем Mac, но не во всех моих Linux-установках Python. По сути, это не один из модулей, перечисленных в Указатель модуля Python.

Acumenus 21.10.2016 07:06

Конечно. Чтобы установить пакет, просто запустите обычный pip install ipython или включите зависимость в свой requirements.txt или pom.xml. Документация: ipython.org/install.html

tashuhka 21.10.2016 11:44

Для этого можно использовать os.listdir:

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

Это не отвечает на вопрос

Georgy 16.05.2019 15:28

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

distutils.dir_util не является частью общедоступного API distutil и имеет проблемы в многопоточных средах: bugs.python.org/issue10948
Pod 27.09.2016 11:26

да. Как отмечено в первое сообщение ошибки, проблема с distutils.dir_util.mkpath заключается в том, что если вы создаете каталог, затем удаляете его изнутри или вне Python, а затем снова используете mkpath, mkpath просто будет использовать свою недопустимую кэшированную информацию о том, что ранее каталог был создан, и фактически не будет создавать каталог снова. Напротив, os.makedirs не полагается на такой кеш.

Acumenus 21.10.2016 07:38

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

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

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

Как это отвечает на вопрос о создание директории?

Georgy 16.05.2019 15:32

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

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

os.makedirs(path,exist_ok=True)

В Python2os.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

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

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

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

Where your code here is use the (touch) command

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

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

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

└── 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

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

 if not os.path.isdir(test_img_dir):
     os.mkdir(test_img_dir)

Вызовите функцию 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')

Почему бы не использовать модуль подпроцесса, если он работает на машине, поддерживающей команду 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...

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

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)

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

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

import os
os.system("mkdir -p {0}".format('mydir'))

Лучше использовать независимые от ОС методы.

OneCricketeer 28.09.2020 20:30

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

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

Другие вопросы по теме