Функциональность mkdir -p в Python [дубликат]
Вопрос
На этот вопрос уже есть ответ здесь:
Есть ли способ получить функциональность, аналогичную mkdir -p
в оболочке изнутри Python.Я ищу решение, отличное от системного вызова.Я уверен, что код меньше 20 строк, и мне интересно, написал ли его кто-нибудь уже?
Решение
mkdir -p
функциональность следующим образом:
import errno
import os
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
Обновлять
Для Python ≥ 3.2, os.makedirs
имеет необязательный третий аргумент exist_ok
это, если оно истинно, позволяет mkdir -p
функциональность —пока не mode
предоставлен, и существующий каталог имеет другие разрешения, чем предполагалось;в таком случае, OSError
поднимается, как и раньше.
Обновление 2
Для Python ≥ 3.5 также существует pathlib.Path.mkdir
:
import pathlib
pathlib.Path("/tmp/path/to/desired/directory").mkdir(parents=True, exist_ok=True)
А exist_ok
параметр был добавлен в Python 3.5.
Другие советы
Это проще, чем перехват исключения:
import os
if not os.path.exists(...):
os.makedirs(...)
Отказ от ответственности Этот подход требует двух системных вызовов, которые более восприимчивы к условиям гонки в определенных средах/условиях.Если вы пишете что-то более сложное, чем простой одноразовый сценарий, работающий в контролируемой среде, вам лучше использовать принятый ответ, требующий только одного системного вызова.
ОБНОВЛЕНИЕ 27 июля 2012 г.
У меня возникает соблазн удалить этот ответ, но я думаю, что ветка комментариев ниже имеет смысл.Поэтому я конвертирую его в вики.
Недавно я нашел это distutils.dir_util.mkpath:
In [17]: from distutils.dir_util import mkpath
In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']
mkdir -p
выдает ошибку, если файл уже существует:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory `/tmp/foo': File exists
Таким образом, усовершенствованием предыдущих предложений могло бы стать повторноеraise
исключение, если os.path.isdir
возвращает False
(при проверке errno.EEXIST
).
(Обновление) См. также это очень похожий вопрос;Я согласен с принятым ответом (и предостережениями), за исключением того, что я бы рекомендовал os.path.isdir
вместо os.path.exists
.
(Обновление) Согласно предложению в комментариях, полная функция будет выглядеть так:
import os
def mkdirp(directory):
if not os.path.isdir(directory):
os.makedirs(directory)
Как упоминалось в других решениях, мы хотим иметь возможность один раз обратиться к файловой системе, имитируя поведение mkdir -p
.Я не думаю, что это возможно сделать, но мы должны подойти как можно ближе.
Сначала код, объяснение позже:
import os
import errno
def mkdir_p(path):
""" 'mkdir -p' in Python """
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
Как показывают комментарии к ответу @tzot, существуют проблемы с проверкой того, можете ли вы создать каталог до того, как вы его фактически создадите:вы не можете сказать, изменил ли кто-то за это время файловую систему.Это также соответствует стилю Python, когда он просит прощения, а не разрешения.
Итак, первое, что нам нужно сделать, это попытаться создать каталог, а затем, если что-то пойдет не так, выяснить, почему.
Как указывает Джейкоб Габриэльсон, один из случаев, которые мы должны искать, — это случай, когда файл уже существует, в который мы пытаемся поместить каталог.
С mkdir -p
:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory '/tmp/foo': File exists
Аналогичным поведением в Python было бы создание исключения.
Так что нам предстоит выяснить, так ли это было.К сожалению, мы не можем.Мы получаем одно и то же сообщение об ошибке от makedirs независимо от того, существует ли каталог (хорошо) или существует файл, препятствующий созданию каталога (плохо).
Единственный способ выяснить, что произошло, — еще раз проверить файловую систему, чтобы увидеть, есть ли там каталог.Если есть, вернитесь молча, иначе вызовите исключение.
Единственная проблема заключается в том, что файловая система сейчас может находиться в другом состоянии, чем при вызове makedirs.например:файл существовал, вызывая сбой makedirs, но теперь на его месте находится каталог.На самом деле это не имеет большого значения, поскольку функция завершится автоматически, не вызывая исключения, только в том случае, если на момент последнего вызова файловой системы каталог существовал.
С Библиотека путей из стандартной библиотеки Python3:
Path(mypath).mkdir(parents=True, exist_ok=True)
Если родители правда, любые пропавшие родители этого пути создаются по мере необходимости;Они создаются с разрешениями по умолчанию без учета режима (имитируя команду POSIX MKDIR -P).Если существующий_OK является false (по умолчанию), FileExisterror повышается, если целевой каталог уже существует.
Если существующий_OK является истинной, исключения FileExisterror будут игнорироваться (то же поведение, что и команда POSIX MKDIR -P), но только в том случае, если последняя компонент пути не является существующим неректорированным файлом.
Изменено в версии 3.5: Добавлен параметр Exist_ok.
Я думаю, что ответ Асы по сути правильный, но вы могли бы немного расширить его, чтобы он действовал как mkdir -p
, или:
import os
def mkdir_path(path):
if not os.access(path, os.F_OK):
os.mkdirs(path)
или
import os
import errno
def mkdir_path(path):
try:
os.mkdirs(path)
except os.error, e:
if e.errno != errno.EEXIST:
raise
Оба они обрабатывают случай, когда путь уже существует молча, но допускают появление других ошибок.
Объявление функции;
import os
def mkdir_p(filename):
try:
folder=os.path.dirname(filename)
if not os.path.exists(folder):
os.makedirs(folder)
return True
except:
return False
Применение :
filename = "./download/80c16ee665c8/upload/backup/mysql/2014-12-22/adclient_sql_2014-12-22-13-38.sql.gz"
if (mkdir_p(filename):
print "Created dir :%s" % (os.path.dirname(filename))
Лично я добился успеха в следующем, но мою функцию, вероятно, следует называть как-то вроде «убедиться, что этот каталог существует»:
def mkdirRecursive(dirpath):
import os
if os.path.isdir(dirpath): return
h,t = os.path.split(dirpath) # head/tail
if not os.path.isdir(h):
mkdirRecursive(h)
os.mkdir(join(h,t))
# end mkdirRecursive
import os
import tempfile
path = tempfile.mktemp(dir=path)
os.makedirs(path)
os.rmdir(path)
import os
from os.path import join as join_paths
def mk_dir_recursive(dir_path):
if os.path.isdir(dir_path):
return
h, t = os.path.split(dir_path) # head/tail
if not os.path.isdir(h):
mk_dir_recursive(h)
new_path = join_paths(h, t)
if not os.path.isdir(new_path):
os.mkdir(new_path)
на основе ответа @Dave C, но с исправленной ошибкой, когда часть дерева уже существует