Дополнительно
Как безопасно создать вложенный каталог?
Какой самый элегантный способ проверить, существует ли каталог, в который будет записан файл, и если нет, создать его с помощью 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", который заставляет это происходить автоматически?
3872
20
Я вижу два ответа с хорошими качествами, каждый из которых имеет небольшой недостаток, поэтому я выскажу свое мнение по этому поводу:
Попробуйте
os.path.exists
, и рассмотритеos.makedirs
для создания.Как отмечалось в комментариях и в других местах, существует – если каталог будет создан между вызовами
os.path.exists
иos.makedirs
, тоos.makedirs
завершится сOSError
. К сожалению, отлавливаниеOSError
и продолжение работы не является надежным, так как при этом будет проигнорирован сбой создания каталога из-за других факторов, таких как недостаточные разрешения, полный диск и т.д.Одним из вариантов может быть перехват
OSError
и изучение встроенного кода ошибки (см. Существует ли кроссплатформенный способ получения информации из OSError в Python):Как вариант, может быть второй
os.path.exists
, но предположим, что другой создал каталог после первой проверки, а затем удалил его до второй – нас все равно могут обмануть.В зависимости от приложения, опасность одновременных операций может быть больше или меньше, чем опасность, исходящая от других факторов, таких как права доступа к файлам. Разработчик должен знать больше о конкретном разрабатываемом приложении и его предполагаемом окружении, прежде чем выбирать реализацию.
Современные версии Python значительно улучшили этот код, как за счет раскрытия
FileExistsError
(в 3.3+)......и разрешением аргумента ключевого слова в
os.makedirs
под названиемexist_ok
(в 3.2+).Python 3.5+:
pathlib.Path.mkdir
, как использовано выше, рекурсивно создает каталог и не вызывает исключения, если каталог уже существует. Если вам не нужно или вы не хотите, чтобы создавались родители, пропустите аргументparents
.Python 3.2+:
Использование
pathlib
:.Если есть возможность, установите текущий бэкпорт
pathlib
под названиемpathlib2
. Не устанавливайте старый необработанный бэкпорт под названиемpathlib
. Далее, обратитесь к разделу о Python 3.5+ выше и используйте его так же.Если вы используете Python 3.4, хотя он и поставляется с
pathlib
, в нем отсутствует полезная опцияexist_ok
. Этот бэкпорт призван предложить более новую и совершенную реализациюmkdir
, которая включает эту недостающую опцию.Использование
os
:.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
:.Хотя в наивном решении сначала может использоваться
os.path.isdir
, а затемos.makedirs
, приведенное выше решение меняет порядок этих двух операций. Это предотвращает распространенное состояние гонки, связанное с дублированием попыток создания каталога, а также позволяет отличить файлы от каталогов.Обратите внимание, что перехват исключения и использование
errno
имеет ограниченную полезность, посколькуOSError: [Errno 17] File exists
, т.е.errno.EEXIST
, возникает как для файлов, так и для каталогов. Надежнее просто проверить, существует ли каталог.Альтернатива:
mkpath
создает вложенный каталог и ничего не делает, если каталог уже существует. Это работает как в Python 2, так и в Python 3.Согласно Bug 10948, серьезным ограничением этой альтернативы является то, что она работает только один раз в каждом процессе python для данного пути. Другими словами, если вы используете его для создания каталога, затем удалите каталог из Python или извне, а затем снова используете
mkpath
для воссоздания того же каталога,mkpath
будет просто молча использовать свою недействительную кэшированную информацию о предыдущем создании каталога, и не будет фактически создавать каталог снова. В отличие от этого,os.makedirs
не полагается ни на какой такой кэш. Это ограничение может быть приемлемым для некоторых приложений.Что касается режима каталога, пожалуйста, обратитесь к документации, если вас это волнует.
Использование try except и правильного кода ошибки из модуля errno избавляет от состояния гонки и является кроссплатформенным:
Другими словами, мы пытаемся создать каталоги, но если они уже существуют, мы игнорируем ошибку. С другой стороны, о любой другой ошибке будет сообщено. Например, если вы предварительно создадите каталог 'a' и снимите с него все разрешения, вы получите
OSError
сerrno.EACCES
(Permission denied, error 13).Я бы лично рекомендую использовать ОС.путь.isdir()
для проверки вместо
ОС.путь.существует()`.Если у вас есть:
И глупо пользовательского ввода:
... Вы'вновь собирается в конечном итоге с папку
именем.и т. д. Когда вы пройдете этот аргумент ОС.makedirs () если тест с ОС.путь.существует()
.Проверьте
os.makedirs
: (Проверяет, существует ли полный путь.) Для обработки факта, что каталог может существовать, перехватываетсяOSError
. (Еслиexist_ok
равноFalse
(по умолчанию), тоOSError
будет вызван, если целевой каталог уже существует).Начиная с Python 3.5,
pathlib.Путь.команды mkdir
имеетexist_ok
флаг:Это рекурсивно создает каталог и не вызывает исключение, если каталог уже существует.
(просто как
ОС.makedirs
получилexist_ok
флаг начиная с Python 3.2 е.г'ОС.makedirs(путь, exist_ok=истина)`)Выводы о специфике этой ситуации
Вы даете конкретный файл в определенный путь, а вы тянете каталог из пути к файлу. Затем убедившись в том, что у вас есть каталог, при попытке открыть файл для чтения. Прокомментировать этот код:
Мы хотим избежать перезаписи функции строение,
реж
. Кроме того,путь_к_файлу
или возможноfullfilepath
- пожалуй лучшее смысловое название, чем "имя файла", так что это будет лучше написано:Вашей конечной целью является, чтобы открыть этот файл, вам первоначально состоянии, для написания, но вы'ре по сути приближаемся к этой цели (на основе кода) такой, который открывает файл для чтения:
При условии открытия для чтения
Зачем вы делаете каталог для файла, который вы ожидаете, чтобы быть там и быть в состоянии прочитать?
Просто попытка открыть файл.
Если каталог или файл, это'т здесь, вы'll получить для себя IOError с номерами ошибка:
ошибка.ENOENT
будет указывать на правильное количество ошибок, независимо от вашей платформы. Вы можете поймать его, если вы хотите, например:При условии, что мы'вновь открывая для написания
Это наверное что вы'вновь желая.
В этом случае, мы, вероятно, еще'т сталкивается в любых условиях гонки. Так что делай так, как тебе, но учтите, что для записи нужно открыть с помощью команды
W
режим (или"", чтобы добавить). Это's также питон рекомендуется использовать контекст-менеджера для открытия файлов.Однако, говорят, у нас есть несколько процессов Python, которые пытаются поставить все свои данные в том же каталоге. Тогда у нас есть разногласия по созданию каталога. В этом случае он'ы лучше, чтобы обернуть вызов
makedirs
в try-except блок.Попробуйте использовать функцию
os.path.exists
.Я поставил следующие вниз. Это's не полностью надежной, хотя.
Теперь, как я говорю, это не очень надежно, потому что мы имеем возможность не создавать каталог, а еще процесс ее создания в течение этого периода.
Прямого ответа на это, предполагая, простой ситуации, когда вы не'т ожидать, что другие пользователи или процессы, чтобы быть возиться с вашего каталога:
или если изготовление каталога зависит от условий гонки (т. е. если после проверки путь существует, что-то другое, возможно, уже сделали это) сделать это:
Но, пожалуй, даже лучший подход, чтобы обойти вопроса конфликтов ресурсов, с помощью временных каталогов через
tempfile
:Здесь'ы Essentials из интернет-дока:
Нового в Python 3.5:
pathlib.Путь
сexist_ok
Там's объекта новый "путь" (как 3.4) с большим количеством методов можно было бы хотеть использовать с путями - одна из которых
команды mkdir
.(Для контекста, Я'м отслеживая мою еженедельную рэп со сценарием. Здесь'ы соответствующие части кода из скрипта, которые позволяют мне избежать удара переполнение стека более чем один раз в день на одни и те же данные.)
Первый соответствующий импорт:
Мы не'т приходится иметь дело с ОС.путь.присоединяйтесь сейчас - просто соединить части пути с
/
:Тогда я идемпотентным образом обеспечить существует каталог - аргумент
exist_ok
появляется в Python 3.5:Здесь's в соответствующей части документация:
Здесь's немного больше сценария - в моем случае, я'м не подлежит гонки, у меня только один процесс, который ожидает каталога (или содержащиеся в ней файлы), чтобы быть там, и я Дон'т иметь все, что пытается удалить каталог.
"Путь" объекты должны быть приведены к ул. перед другими API, которые ожидают
ул.
пути могут их использовать.Возможно, панды должны быть обновлены, чтобы принять экземпляры абстрактный базовый класс, ОС.PathLike`.
В Python 3.4 вы также можете использовать [модуль новый
pathlib
] (https://docs.python.org/3/library/pathlib.html):Соответствующим документации Python рекомендует использовать EAFP стиль кодирования (проще попросить прощения, чем разрешения). Это означает, что код
это лучше, чем альтернатива
Документация предполагает, что это именно из-за состояния гонки, обсуждали этот вопрос. Кроме того, как говорят здесь, есть преимущество в производительности в один запрос вместо двух ОС. Наконец, аргумент смещен вперед, потенциально, в пользу второго кода в некоторых случаях, когда разработчик знает среду выполнения приложения-только может быть выступал в особом случае, что программа была создана частная условий для себя (и других экземпляров той же программе).
Даже в этом случае, это плохая практика и может привести к длительным бесполезным отладки. Например, тот факт, что мы установить разрешения для папки не должно покидать нас с разрешения впечатление заданы правильно для наших целей. Родительского каталога может быть установлен с другими разрешениями. В общем, программа всегда должна работать правильно, и программист не должен ждать определенной среде.
В Питон3,
ОС.makedirs` поддерживает параметр
exist_ok. Значение по умолчанию
ложь, которое означает ``OSError
будет повышено, если целевой каталог уже существует. Установивexist_ok
вПравда
,OSError
(каталог существует) будет игнорироваться, а каталог не будет создан.В Вместо python2,
ОС.makedirs
не'поддержка t параметрexist_ok
. Вы можете использовать этот подход в Хейкки-Тойвонен'ы ответ:Вы можете использовать
mkpath
Обратите внимание, что это создаст каталоги предка, а также.
Это работает для Python 2 и 3.
Для однострочное решение, вы можете использовать
IPython.utils.path.ensure_dir_exists()
:В документации: Ensure, что существует каталог. Если он не существует, попробуйте создать его и защитить от гонки, если другой процесс делает то же самое.
Я использую ОС.путь.существует()`, здесь это скрипт на Python 3, который может использоваться, чтобы проверить, если каталог существует, создайте его, если его не существует, и удалить его, если он существует (при желании).
Он предлагает пользователю для ввода директории и могут быть легко изменены.
Вы можете использовать `ОС.listdir для этого:
Я видел Хейкки Тойвонен и А-Б-Б's отвечает и думал о этом варианте.
Я нашел этот Q/A и я был поначалу озадачен некоторые сбои и ошибки я получаю. Я работаю в Python 3 (в. 3.5 в виртуальной Анаконда среды на систему Arch Linux на архитектуру x86_64).
Рассмотрим эту структуру каталогов:
Вот мои эксперименты/ноты, которая многое объясняет:
Вывод: на мой взгляд, "и Метод 2" и является более надежной.
[1] https://stackoverflow.com/questions/273192/how-can-i-create-a-directory-if-it-does-not-exist
[2] https://docs.python.org/3/library/os.html#os.makedirs
Если вы рассмотрите следующее:
значит, существует каталог (путь) и является каталогом. Так что для меня этот способ делает то, что мне нужно. Так что я могу убедиться, что это папка (а не файл) и существует.