Есть ли способ получить функциональность, похожую на mkdir -p
на оболочку из Python. Я ищу решение, отличное от системного. Я уверен, что код меньше 20 строк, и мне интересно, кто-то уже написал его?
Функциональность mkdir -p в Python
Ответ 1
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
Update
Для Python ≥ 3.2, os.makedirs
имеет необязательный третий аргумент exist_ok
, который, когда true, включает функциональность 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.
Ответ 2
В Python >= 3.2 это
os.makedirs(path, exist_ok=True)
В более ранних версиях используйте @tzot answer.
Ответ 3
Это проще, чем захват исключения:
import os
if not os.path.exists(...):
os.makedirs(...)
Отказ от ответственности Этот подход требует двух системных вызовов, которые более подвержены условиям гонки в определенных условиях/условиях. Если вы пишете что-то более сложное, чем простая утилита script, работающая в контролируемой среде, вам лучше идти с принятым ответом, для которого требуется только один системный вызов.
ОБНОВЛЕНИЕ 2012-07-27
У меня возникает соблазн удалить этот ответ, но я думаю, что здесь есть значение в потоке комментариев. Таким образом, я конвертирую его в wiki.
Ответ 4
В последнее время я нашел это distutils.dir_util.mkpath:
In [17]: from distutils.dir_util import mkpath
In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']
Ответ 5
mkdir -p
выдает сообщение об ошибке, если файл уже существует:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory `/tmp/foo': File exists
Таким образом, уточнение предыдущих предложений состояло бы в том, чтобы исключить исключение, если os.path.isdir
возвращает False
(при проверке на errno.EEXIST
).
(Update) См. также этот очень похожий вопрос; Я согласен с принятым ответом (и оговорками), за исключением того, что я рекомендовал бы os.path.isdir
вместо os.path.exists
.
(Обновление). По предложению в комментариях полная функция будет выглядеть так:
import os
def mkdirp(directory):
if not os.path.isdir(directory):
os.makedirs(directory)
Ответ 6
Как упоминалось в других решениях, мы хотим иметь возможность ударить файловую систему один раз, при этом имитируя поведение 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 терпят неудачу, но теперь на его месте находится каталог. Это не имеет большого значения, потому что функция будет работать только без молчания, не создавая исключения, когда во время последней файловой системы вызывал каталог.
Ответ 7
С Pathlib из стандартной библиотеки python3:
Path(mypath).mkdir(parents=True, exist_ok=True)
Если родители верны, любые отсутствующие родители этого пути создаются как необходимости; они создаются с разрешениями по умолчанию, не принимая (имитируя команду POSIX mkdir -p). Если exist_ok является ложным (по умолчанию), FileExistsError возникает, если целевой каталог уже существует.
Если exists_ok истинно, исключения FileExistsError будут игнорироваться (то же самое поведение как команда POSIX mkdir -p), но только если последний путь компонент не является существующим файлом без каталога.
Изменено в версии 3.5: Добавлен параметр exist_ok.
Ответ 8
Я думаю, что ответ Asa, по сути, правильный, но вы можете немного расширить его, чтобы больше походить на 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
Они оба обрабатывают случай, когда путь уже существует молча, но допускают появление других ошибок.
Ответ 9
Объявление функции;
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))
Ответ 10
import os
import tempfile
path = tempfile.mktemp(dir=path)
os.makedirs(path)
os.rmdir(path)
Ответ 11
У меня был успех со следующим лично, но моя функция должна, вероятно, называться чем-то вроде "обеспечить, чтобы этот каталог существовал":
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
Ответ 12
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, но с исправленной ошибкой, когда часть дерева уже существует