Какой самый элегантный способ проверить, существует ли каталог, в который будет записан файл, и если нет, создать его с помощью 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", который заставляет это происходить автоматически?
Я вижу два ответа с хорошими качествами, каждый из которых имеет небольшой недостаток, поэтому я выскажу свое мнение по этому поводу:
Попробуйте 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
и изучение встроенного кода ошибки (см. Существует ли кроссплатформенный способ получения информации из OSError в Python):
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.
import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True)
pathlib.Path.mkdir
, как использовано выше, рекурсивно создает каталог и не вызывает исключения, если каталог уже существует. Если вам не нужно или вы не хотите, чтобы создавались родители, пропустите аргумент parents
.
Использование 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
, как использовано выше, рекурсивно создает каталог и не вызывает исключения, если каталог уже существует. Опциональный аргумент exist_ok
доступен только при использовании Python 3.2+, по умолчанию он имеет значение False
. В Python 2.x до версии 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, так и в Python 3.
import distutils.dir_util
distutils.dir_util.mkpath(path)
Согласно Bug 10948, серьезным ограничением этой альтернативы является то, что она работает только один раз в каждом процессе python для данного пути. Другими словами, если вы используете его для создания каталога, затем удалите каталог из Python или извне, а затем снова используете mkpath
для воссоздания того же каталога, mkpath
будет просто молча использовать свою недействительную кэшированную информацию о предыдущем создании каталога, и не будет фактически создавать каталог снова. В отличие от этого, os.makedirs
не полагается ни на какой такой кэш. Это ограничение может быть приемлемым для некоторых приложений.
Что касается режима каталога, пожалуйста, обратитесь к документации, если вас это волнует.
Использование 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).
Я бы лично рекомендую использовать ОС.путь.isdir()для проверки вместо
ОС.путь.существует()`.
>>> 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
... Вы'вновь собирается в конечном итоге с папку именем.и т. д. Когда вы пройдете этот аргумент ОС.makedirs () если тест с ОС.путь.существует()
.
Проверьте os.makedirs
: (Проверяет, существует ли полный путь.)
Для обработки факта, что каталог может существовать, перехватывается OSError
.
(Если exist_ok
равно False
(по умолчанию), то OSError
будет вызван, если целевой каталог уже существует).
import os
try:
os.makedirs('./path/to/somewhere')
except OSError:
pass
Начиная с Python 3.5, pathlib.Путь.команды 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)
Это рекурсивно создает каталог и не вызывает исключение, если каталог уже существует.
(просто как ОС.makedirs
получил exist_ok
флаг начиная с Python 3.2 е.г'ОС.makedirs(путь, exist_ok=истина)`)
Вы даете конкретный файл в определенный путь, а вы тянете каталог из пути к файлу. Затем убедившись в том, что у вас есть каталог, при попытке открыть файл для чтения. Прокомментировать этот код:
имяфайла = " По - /мой/каталог/именем.тхт"и реж = ОС.путь.каталог(именем)
Мы хотим избежать перезаписи функции строение, реж
. Кроме того, путь_к_файлу
или возможно fullfilepath
- пожалуй лучшее смысловое название, чем "имя файла", так что это будет лучше написано:
import os
filepath = '/my/directory/filename.txt'
directory = os.path.dirname(filepath)
Вашей конечной целью является, чтобы открыть этот файл, вам первоначально состоянии, для написания, но вы'ре по сути приближаемся к этой цели (на основе кода) такой, который открывает файл для чтения:
если не ОС.путь.существует(каталог): ОС.makedirs(каталог) F = файл(имя файла)
Зачем вы делаете каталог для файла, который вы ожидаете, чтобы быть там и быть в состоянии прочитать?
Просто попытка открыть файл.
with open(filepath) as my_file:
do_stuff(my_file)
Если каталог или файл, это'т здесь, вы'll получить для себя IOError с номерами ошибка: ошибка.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
режим (или"", чтобы добавить). Это's также питон рекомендуется использовать контекст-менеджера для открытия файлов.
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)
Попробуйте использовать функцию os.path.exists
.
if not os.path.exists(dir):
os.mkdir(dir)
Я поставил следующие вниз. Это's не полностью надежной, хотя.
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
Теперь, как я говорю, это не очень надежно, потому что мы имеем возможность не создавать каталог, а еще процесс ее создания в течение этого периода.
проверить, существует ли каталог и создайте ее при необходимости?
Прямого ответа на это, предполагая, простой ситуации, когда вы не'т ожидать, что другие пользователи или процессы, чтобы быть возиться с вашего каталога:
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()
Здесь'ы Essentials из интернет-дока:
mkdtemp(суффикс='', префикс='tпл', Дир=нет) вызываемые пользователем функции, чтобы создать и вернуть уникальные временные каталог. Возвращаемым значением является имя пути каталога.
каталог чтение, запись и просмотр только создание пользователей.
абонент отвечает за удаление каталога, когда покончим с этим.
pathlib.Путь
с exist_ok
Там's объекта новый "путь" (как 3.4) с большим количеством методов можно было бы хотеть использовать с путями - одна из которых команды mkdir
.
(Для контекста, Я'м отслеживая мою еженедельную рэп со сценарием. Здесь'ы соответствующие части кода из скрипта, которые позволяют мне избежать удара переполнение стека более чем один раз в день на одни и те же данные.)
Первый соответствующий импорт:
from pathlib import Path
import tempfile
Мы не'т приходится иметь дело с ОС.путь.присоединяйтесь сейчас - просто соединить части пути с /
:
directory = Path(tempfile.gettempdir()) / 'sodata'
Тогда я идемпотентным образом обеспечить существует каталог - аргумент exist_ok
появляется в Python 3.5:
directory.mkdir(exist_ok=True)
Здесь's в соответствующей части документация:
если
exist_ok
это правда,FileExistsError
исключения будут игнорироваться (так же, как и команды команды mkdir-р в POSIX`), но только если последний компонент пути не существующей директории файл.
Здесь's немного больше сценария - в моем случае, я'м не подлежит гонки, у меня только один процесс, который ожидает каталога (или содержащиеся в ней файлы), чтобы быть там, и я Дон'т иметь все, что пытается удалить каталог.
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))
"Путь" объекты должны быть приведены к ул. перед другими API, которые ожидают ул.
пути могут их использовать.
Возможно, панды должны быть обновлены, чтобы принять экземпляры абстрактный базовый класс, ОС.PathLike`.
В Python 3.4 вы также можете использовать [модуль новый pathlib
] (https://docs.python.org/3/library/pathlib.html):
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.
Соответствующим документации 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
Документация предполагает, что это именно из-за состояния гонки, обсуждали этот вопрос. Кроме того, как говорят здесь, есть преимущество в производительности в один запрос вместо двух ОС. Наконец, аргумент смещен вперед, потенциально, в пользу второго кода в некоторых случаях, когда разработчик знает среду выполнения приложения-только может быть выступал в особом случае, что программа была создана частная условий для себя (и других экземпляров той же программе).
Даже в этом случае, это плохая практика и может привести к длительным бесполезным отладки. Например, тот факт, что мы установить разрешения для папки не должно покидать нас с разрешения впечатление заданы правильно для наших целей. Родительского каталога может быть установлен с другими разрешениями. В общем, программа всегда должна работать правильно, и программист не должен ждать определенной среде.
В Питон3, ОС.makedirs` поддерживает параметр
exist_ok. Значение по умолчанию
ложь, которое означает ``OSError
будет повышено, если целевой каталог уже существует. Установив exist_ok
в Правда
, OSError
(каталог существует) будет игнорироваться, а каталог не будет создан.
os.makedirs(path,exist_ok=True)
В Вместо python2, ОС.makedirs
не'поддержка t параметр 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
Вы можете использовать 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.
Для однострочное решение, вы можете использовать IPython.utils.path.ensure_dir_exists()
:
from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)
В документации: Ensure, что существует каталог. Если он не существует, попробуйте создать его и защитить от гонки, если другой процесс делает то же самое.
Я использую ОС.путь.существует()`, здесь это скрипт на Python 3, который может использоваться, чтобы проверить, если каталог существует, создайте его, если его не существует, и удалить его, если он существует (при желании).
Он предлагает пользователю для ввода директории и могут быть легко изменены.
Я видел Хейкки Тойвонен и А-Б-Б's отвечает и думал о этом варианте.
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
Я нашел этот Q/A и я был поначалу озадачен некоторые сбои и ошибки я получаю. Я работаю в Python 3 (в. 3.5 в виртуальной Анаконда среды на систему 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] https://stackoverflow.com/questions/273192/how-can-i-create-a-directory-if-it-does-not-exist
Если вы рассмотрите следующее:
os.path.isdir('/tmp/dirname')
значит, существует каталог (путь) и является каталогом. Так что для меня этот способ делает то, что мне нужно. Так что я могу убедиться, что это папка (а не файл) и существует.