Каков наиболее элегантный способ проверить, существует ли каталог, в который будет записан файл, и, если нет, создать каталог с помощью 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)
Есть ли флаг «открыть», который делает это автоматически?
os.path.mkdir
не существует. Этоos.mkdir
.p
, вот мой фрагмент кода:os.makedirs(p[:p.rindex(os.path.sep)], exist_ok=True)
Ответы:
На Python ≥ 3.5 используйте
pathlib.Path.mkdir
:Для более старых версий Python я вижу два ответа с хорошими качествами, каждый с небольшим недостатком, поэтому я сделаю это:
Попробуйте
os.path.exists
и рассмотритеos.makedirs
для создания.Как отмечено в комментариях и в других местах, существует условие состязания - если каталог создается между вызовами
os.path.exists
иos.makedirs
вызовами,os.makedirs
произойдет сбой с помощьюOSError
. К сожалению, общий поискOSError
и продолжение не являются надежными, так как они будут игнорировать сбой при создании каталога из-за других факторов, таких как недостаточные разрешения, полный диск и т. Д.Один из вариантов - перехватить
OSError
и изучить встроенный код ошибки (см. Существует ли кроссплатформенный способ получения информации из Python OSError ):В качестве альтернативы может существовать второй
os.path.exists
, но предположим, что другой создал каталог после первой проверки, а затем удалил его до второй проверки - нас все еще можно обмануть.В зависимости от приложения опасность одновременных операций может быть больше или меньше опасности других факторов, таких как права доступа к файлам. Разработчик должен знать больше о конкретном разрабатываемом приложении и его ожидаемой среде, прежде чем выбирать реализацию.
Современные версии Python немного улучшают этот код, предоставляя
FileExistsError
(в версии 3.3+ ) ...... и позволяя ключевому аргументу
os.makedirs
вызыватьсяexist_ok
(в 3.2+).источник
os.path.exists
также возвращаетсяTrue
для файла. Я отправил ответ на этот вопрос.exists_ok
параметр toos.makedirs()
может использоваться для описания того, как обрабатывается предшествующее существование пути, начиная с Python 3.2.os.mkdirs()
может создавать непреднамеренные папки, если разделитель пути случайно пропущен, текущая папка не соответствует ожидаемой, элемент пути содержит разделитель пути. Если вы используетеos.mkdir()
эти ошибки, возникнет исключение, предупреждающее вас об их существовании.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, так и в 3.В соответствии с ошибкой 10948 , серьезным ограничением этой альтернативы является то, что она работает только один раз на процесс python для данного пути. Другими словами, если вы используете его для создания каталога, затем удаляете каталог изнутри или снаружи Python, а затем
mkpath
снова используете для воссоздания того же каталога,mkpath
просто молча будут использовать его неверную кэшированную информацию о том, что ранее создали каталог, и не будут на самом деле сделать каталог снова. Напротив,os.makedirs
не полагается на любой такой кэш. Это ограничение может быть в порядке для некоторых приложений.Что касается режима каталога , пожалуйста, обратитесь к документации, если вы заботитесь о нем.
источник
os.path.isdir
кто-то еще удаляет папку, вы увидите ошибку, которая устарела и устарела, эта папка существует.Использование try кроме и правильного кода ошибки из модуля errno избавляет от состояния гонки и является кроссплатформенным:
Другими словами, мы пытаемся создать каталоги, но если они уже существуют, мы игнорируем ошибку. С другой стороны, сообщается о любой другой ошибке. Например, если вы заранее создадите dir 'a' и удалите из него все разрешения, вы получите
OSError
повышение сerrno.EACCES
(Отказано в доступе, ошибка 13).источник
exception.errno != errno.EEXIST
непреднамеренно проигнорирует случай, когда путь существует, но это не-каталогный объект, такой как файл. В идеале, исключение следует вызывать, если путь не является каталогом.os.makedirs(path,exist_ok=True)
exist_ok
Параметр был введен в Python 3.2. Его нет в Python 2.x. Я включу это в свой ответ.Я бы лично рекомендовал вам использовать
os.path.isdir()
для тестирования вместоos.path.exists()
.Если у тебя есть:
И глупый пользовательский ввод:
... Вы
filename.etc
получите каталог с именем, когда передадите этот аргумент,os.makedirs()
если будете тестировать сos.path.exists()
.источник
Проверьте
os.makedirs
: (Он гарантирует, что полный путь существует.)Чтобы обработать тот факт, что каталог может существовать, перехватите
OSError
. (Еслиexist_ok
естьFalse
(по умолчанию), тоOSError
поднимается, если целевой каталог уже существует.)источник
OSError
будет поднят здесь, если путь является существующим файлом или каталогом. Я отправил ответ на этот вопрос.OSError
прежде чем принимать решение игнорировать его. См. Stackoverflow.com/a/5032238/763269 .Начиная с Python 3.5,
pathlib.Path.mkdir
естьexist_ok
флаг:Это рекурсивно создает каталог и не вызывает исключение, если каталог уже существует.
(так же, как
os.makedirs
получилexist_ok
флаг, начиная с Python 3.2, напримерos.makedirs(path, exist_ok=True)
)источник
Понимание специфики этой ситуации
Вы указываете конкретный файл по определенному пути и извлекаете каталог из пути к файлу. Затем, убедившись, что у вас есть каталог, вы пытаетесь открыть файл для чтения. Чтобы прокомментировать этот код:
Мы хотим избежать перезаписи встроенной функции
dir
. Кроме того,filepath
или, возможно,fullfilepath
это, вероятно, лучшее семантическое имя, чемfilename
это было бы лучше написать:Ваша конечная цель состоит в том, чтобы открыть этот файл, который вы изначально заявляете, для записи, но вы, по сути, приближаетесь к этой цели (основываясь на вашем коде) следующим образом, открывая файл для чтения :
Предполагая открытие для чтения
Зачем вам делать каталог для файла, который вы ожидаете там и сможете прочитать?
Просто попробуйте открыть файл.
Если каталог или файл отсутствуют, вы получите
IOError
соответствующий номер ошибки: онerrno.ENOENT
будет указывать на правильный номер ошибки независимо от вашей платформы. Вы можете поймать его, если хотите, например:Предполагая, что мы открыты для записи
Это наверное то, что вы хотите.
В этом случае мы, вероятно, не сталкиваемся ни с какими расами. Так что просто делайте, как вы, но учтите, что для записи вам нужно открыть с помощью
w
режима (илиa
добавить). На Python также рекомендуется использовать менеджер контекста для открытия файлов.Однако, скажем, у нас есть несколько процессов Python, которые пытаются поместить все свои данные в один и тот же каталог. Тогда мы можем иметь разногласия по поводу создания каталога. В этом случае лучше всего обернуть
makedirs
вызов в блок try-Кроме.источник
Попробуйте
os.path.exists
функциюисточник
os.path.mkdir()
метода. Модуль os.path реализует некоторые полезные функции для путей .Я изложил следующее. Это не совсем надежно, хотя.
Теперь, как я уже сказал, это не совсем надежно, потому что у нас есть возможность не создать каталог и создать другой процесс в течение этого периода.
источник
os.path.exists
- см. Stackoverflow.com/a/5032238/763269, и (2) успехos.path.exists
не означает, что каталог существует, просто путь существует - это может быть файл, символическая ссылка или другой объект файловой системы.Прямой ответ на этот вопрос заключается в предположении простой ситуации, когда вы не ожидаете, что другие пользователи или процессы будут связываться с вашим каталогом:
или если создание каталога зависит от условий гонки (т. е. если после проверки пути существует, что-то еще, возможно, уже сделало это), сделайте это:
Но, возможно, еще лучший подход - обойти проблему конфликта ресурсов, используя временные каталоги с помощью
tempfile
:Вот основные сведения из онлайн-документа:
Новое в Python 3.5:
pathlib.Path
сexist_ok
Есть новый
Path
объект (начиная с 3.4) с множеством методов, которые можно использовать с путями - один из которых естьmkdir
.(Для контекста я отслеживаю своего еженедельного представителя с помощью скрипта. Вот соответствующие части кода из скрипта, которые позволяют мне избегать переполнения стека более одного раза в день для одних и тех же данных.)
Сначала соответствующий импорт:
Нам не нужно иметь дело
os.path.join
сейчас - просто соедините части пути с помощью/
:Затем я идемпотентно гарантирую, что каталог существует -
exist_ok
аргумент обнаруживается в Python 3.5:Вот соответствующая часть документации :
Вот немного больше сценария - в моем случае я не подвержен условию гонки, у меня есть только один процесс, который ожидает, что каталог (или содержащиеся файлы) будет там, и у меня нет ничего, что пыталось бы удалить каталог.
Path
объекты должны быть приведены к тому,str
чтобы другие API, ожидающиеstr
пути, могли их использовать.Возможно, Панды должны быть обновлены, чтобы принимать экземпляры абстрактного базового класса
os.PathLike
.источник
В Python 3.4 вы также можете использовать новый
pathlib
модуль :источник
pathlib
и гдеpathlib2
для новых пользователей, и я думаю, что профессионалы здесь определятся с устареванием;)В соответствующей документации по Python предлагается использовать стиль кодирования EAFP (проще просить прощения, чем разрешения) . Это означает, что код
лучше альтернативы
Документация предполагает это именно из-за состояния гонки, обсуждаемого в этом вопросе. Кроме того, как другие упоминают здесь, есть преимущество в производительности при запросе один раз, а не дважды ОС. Наконец, аргумент, выдвигаемый, возможно, в пользу второго кода в некоторых случаях - когда разработчик знает среду, в которой выполняется приложение - может быть защищен только в том особом случае, когда программа создала частную среду для сам (и другие экземпляры той же программы).
Даже в этом случае это плохая практика и может привести к длительной бесполезной отладке. Например, тот факт, что мы устанавливаем права доступа для каталога, не должен оставлять нас с впечатлением, что права доступа установлены для наших целей. Родительский каталог может быть смонтирован с другими разрешениями. В общем, программа должна всегда работать правильно, и программист не должен ожидать одну конкретную среду.
источник
В Python3 ,
os.makedirs
установка опорexist_ok
. По умолчанию используется значениеFalse
, которое означает, чтоOSError
будет поднято, если целевой каталог уже существует. Установивexist_ok
вTrue
,OSError
(каталог существует) будет игнорироваться и каталог не будет создан.В python2 ,
os.makedirs
не поддерживает установкуexist_ok
. Вы можете использовать подход в ответе Хейкки-Тойвонена :источник
Для однострочного решения вы можете использовать
IPython.utils.path.ensure_dir_exists()
:Из документации : убедитесь, что каталог существует. Если он не существует, попытайтесь создать его и защитить от состояния гонки, если другой процесс делает то же самое.
источник
IPython
Модуль абсолютно не гарантированно присутствовать. Он изначально присутствует на моем Mac, но не на любом из моих Linux-установок Python. По сути, это не один из модулей, перечисленных в указателе модулей Python .pip install ipython
или включить зависимость в вашем requirements.txt или pom.xml . Документация: ipython.org/install.htmlТы можешь использовать
mkpath
Обратите внимание, что он также создаст каталоги предков.
Это работает для Python 2 и 3.
источник
distutils.dir_util
не является частью distutil public API и имеет проблемы в многопоточных средах: bugs.python.org/issue10948distutils.dir_util.mkpath
том, что если вы создаете каталог, затем удаляете его изнутри или снаружи Python, а затемmkpath
снова используете ,mkpath
просто воспользуетесь неверной кэшированной информацией о том, что ранее создал каталог, и на самом деле не сделать каталог снова. Напротив,os.makedirs
не полагается на любой такой кэш.Я использую
os.path.exists()
, вот сценарий Python 3, который можно использовать для проверки, существует ли каталог, создать его, если он не существует, и удалить его, если он существует (при желании).Он предлагает пользователям ввести каталог и может быть легко изменен.
источник
Вы можете использовать
os.listdir
для этого:источник
Я нашел это Q / A, и я был первоначально озадачен некоторыми сбоями и ошибками, которые я получал. Я работаю в Python 3 (v.3.5 в виртуальной среде Anaconda в системе Arch Linux x86_64).
Рассмотрим эту структуру каталогов:
Вот мои эксперименты / заметки, которые проясняют вещи:
Вывод: по моему мнению, «Метод 2» является более надежным.
[1] Как я могу создать каталог, если он не существует?
[2] https://docs.python.org/3/library/os.html#os.makedirs
источник
Я видел ответы Хейкки Тойвонена и АББ и думал об этом варианте.
источник
Используйте эту команду, проверьте и создайте каталог
источник
Почему бы не использовать модуль подпроцесса, если он работает на компьютере, который поддерживает команду
mkdir
с-p
параметром? Работает на Python 2.7 и Python 3.6Должен сделать трюк на большинстве систем.
В ситуациях, когда переносимость не имеет значения (например, с помощью Docker), решение состоит из двух строк. Вам также не нужно добавлять логику, чтобы проверить, существуют ли каталоги или нет. Наконец, безопасно перезапускать без каких-либо побочных эффектов
Если вам нужна обработка ошибок:
источник
Если вы считаете следующее:
означает, что каталог (путь) существует И является каталогом. Так что для меня этот путь делает то, что мне нужно. Поэтому я могу убедиться, что это папка (а не файл) и существует.
источник
Вызовите функцию
create_dir()
в точке входа вашей программы / проекта.источник
Вы должны установить полный путь перед созданием каталога:
Это работает для меня и, надеюсь, это будет работать и для вас
источник
Это проверит, если файл там, если это не так, то он создаст его.
источник