Функциональность mkdir -p в Python [дубликат]

StackOverflow https://stackoverflow.com/questions/600268

  •  03-07-2019
  •  | 
  •  

Вопрос

На этот вопрос уже есть ответ здесь:

Есть ли способ получить функциональность, аналогичную 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.

Другие советы

В Python >=3.2 это

os.makedirs(path, exist_ok=True)

В более ранних версиях используйте ответ @tzot.

Это проще, чем перехват исключения:

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, но с исправленной ошибкой, когда часть дерева уже существует

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top