[python] Как создать каталог, если он не существует?


Answers

Python 3.5+:

import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True) 

pathlib.Path.mkdir как используется выше, рекурсивно создает каталог и не вызывает исключения, если каталог уже существует. Если вам не нужны или хотите, чтобы родители были созданы, пропустите аргумент parents .

Python 3.2+:

Использование pathlib :

Если вы можете, установите текущий pathlib именем pathlib2 . Не устанавливайте старый резервный резервный файл с именем pathlib . Далее, обратитесь к разделу Python 3.5+ выше и используйте его то же самое.

Если использовать Python 3.4, даже если он поставляется с pathlib , backport предназначен для более новой и превосходной реализации mkdir .

Использование os :

import os
os.makedirs(path, exist_ok=True)

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 :

import os
try: 
    os.makedirs(path)
except OSError:
    if not os.path.isdir(path):
        raise

В то время как наивное решение может сначала использовать os.path.isdir за которым следует os.makedirs , решение выше меняет порядок двух операций. При этом он предотвращает общее состояние гонки, связанное с дублированной попыткой создания каталога, а также устраняет неоднозначность файлов из каталогов.

Обратите внимание, что захват исключения и использование errno имеет ограниченную полезность, поскольку OSError: [Errno 17] File exists , т.е. errno.EEXIST , errno.EEXIST как для файлов, так и для каталогов. Более надежно просто проверить, существует ли каталог.

Альтернатива:

mkpath создает вложенный каталог и ничего не делает, если каталог уже существует. Это работает как на Python 2, так и на 3.

import distutils.dir_util
distutils.dir_util.mkpath(path)

Per Bug 10948 , серьезным ограничением этой альтернативы является то, что она работает только один раз на процесс python для заданного пути. Другими словами, если вы используете его для создания каталога, затем удалите каталог изнутри или за пределами Python, затем снова используйте mkpath для воссоздания одного и того же каталога, mkpath просто молча использует свою недопустимую кешированную информацию о том, что ранее создала каталог, и на самом деле не сделает каталог снова. Напротив, os.makedirs не полагается на такой кеш. Это ограничение может быть в порядке для некоторых приложений.

Что касается режима каталога, обратитесь к документации, если вам это нравится.

Question

Какой самый элегантный способ проверить, будет ли каталог, в который будет записываться файл, существует, а если нет, создайте каталог с помощью 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)

Есть ли флаг для «open», что делает это автоматически?




Используйте эту команду для проверки и создания каталога

 if not os.path.isdir(test_img_dir):
     os.mkdir(str("./"+test_img_dir))



Понимание специфики этой ситуации

Вы указываете конкретный файл по определенному пути, и вы вытаскиваете каталог из пути к файлу. Затем, убедившись, что у вас есть каталог, вы пытаетесь открыть файл для чтения. Чтобы прокомментировать этот код:

filename = "/my/directory/filename.txt"
dir = os.path.dirname(filename)

Мы хотим избежать перезаписи встроенной функции, dir . Кроме того, filepath или, возможно, fullfilepath , вероятно, является лучшим семантическим именем, чем filename поэтому это было бы лучше написано:

import os
filepath = '/my/directory/filename.txt'
directory = os.path.dirname(filepath)

Ваша конечная цель - открыть этот файл, который вы изначально указываете для написания, но вы, по сути, приближаетесь к этой цели (на основе вашего кода), которая открывает файл для чтения :

if not os.path.exists(directory):
    os.makedirs(directory)
f = file(filename)

Предполагая открытие для чтения

Почему вы создадите каталог для файла, который вы ожидаете там, и сможете читать?

Просто попробуйте открыть файл.

with open(filepath) as my_file:
    do_stuff(my_file)

Если каталога или файла нет, вы получите IOError с соответствующим номером ошибки: errno.ENOENT укажет на правильный номер ошибки, независимо от вашей платформы. Вы можете поймать его, если хотите, например:

import errno
try:
    with open(filepath) as my_file:
        do_stuff(my_file)
except IOError as error:
    if error.errno == errno.ENOENT:
        print 'ignoring error because directory or file is not there'
    else:
        raise

Предполагая, что мы открываем для написания

Вероятно, это то, чего вы хотите.

В этом случае мы, вероятно, не сталкиваемся с какими-либо условиями гонки. Так что делайте то же, что и вы, но обратите внимание, что для записи вам нужно открыть режим w (или добавить). Это также лучшая практика Python для использования диспетчера контекстов для открытия файлов.

import os
if not os.path.exists(directory):
    os.makedirs(directory)
with open(filepath, 'w') as my_file:
    do_stuff(my_file)

Однако, скажем, у нас есть несколько процессов Python, которые пытаются поместить все свои данные в один и тот же каталог. Тогда у нас может возникнуть вопрос о создании каталога. В этом случае лучше всего makedirs вызов makedirs в блок try-except.

import os
import errno
if not os.path.exists(directory):
    try:
        os.makedirs(directory)
    except OSError as error:
        if error.errno != errno.EEXIST:
            raise
with open(filepath, 'w') as my_file:
    do_stuff(my_file)



При работе с файловыми вводами-выводами важно рассмотреть

TOCTTOU (время проверки на время использования)

Таким образом, проверка с помощью if и последующего чтения или записи позже может закончиться необработанным исключением ввода-вывода. Лучший способ сделать это:

try:
    os.makedirs(dir_path)
except OSError as e:
    if e.errno != errno.EEXIS:
        raise



Я использую os.path.exists() , here скрипт Python 3, который можно использовать для проверки наличия каталога, создать его, если он не существует, и удалить его, если он существует (при желании).

Он предлагает пользователям вводить каталог и может быть легко изменен.




Я лично рекомендовал бы использовать os.path.isdir() для тестирования вместо os.path.exists() .

>>> os.path.exists('/tmp/dirname')
True
>>> os.path.exists('/tmp/dirname/filename.etc')
True
>>> os.path.isdir('/tmp/dirname/filename.etc')
False
>>> os.path.isdir('/tmp/fakedirname')
False

Если у вас есть:

>>> dir = raw_input(":: ")

И глупый пользовательский ввод:

:: /tmp/dirname/filename.etc

... В конце вы получите каталог с именем filename.etc когда вы передадите этот аргумент os.makedirs() если вы проверите с os.path.exists() .




Я поставил следующее. Однако это не совсем безопасно.

import os

dirname = 'create/me'

try:
    os.makedirs(dirname)
except OSError:
    if os.path.exists(dirname):
        # We are nearly safe
        pass
    else:
        # There was an error on creation, so make sure we know about it
        raise

Теперь, как я уже сказал, это не является действительно надежным, потому что у нас есть возможность не создавать каталог и другой процесс, создающий его в течение этого периода.




Я видел ответы Хейкки Тойвонен и share и думал об этом варианте.

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST or not os.path.isdir(path):
            raise



import os
if os.path.isfile(filename):
    print "file exists"
else:
    "Your code here"

Если в вашем коде используется команда (touch)

Это будет проверять, есть ли файл, если он нет, тогда он его создаст.




Для однострочного решения вы можете использовать IPython.utils.path.ensure_dir_exists() :

from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)

Из documentation : убедитесь, что каталог существует. Если этого не существует, попробуйте создать его и защитить от состояния гонки, если другой процесс делает то же самое.




Соответствующая документация на Python предлагает использовать стиль кодирования EAFP (проще просить прощения, чем разрешения) . Это означает, что код

try:
    os.makedirs(path)
except OSError as exception:
    if exception.errno != errno.EEXIST:
        raise
    else:
        print "\nBE CAREFUL! Directory %s already exists." % path

лучше, чем альтернатива

if not os.path.exists(path):
    os.makedirs(path)
else:
    print "\nBE CAREFUL! Directory %s already exists." % path

Документация предполагает это именно из-за состояния гонки, обсуждаемого в этом вопросе. Кроме того, как упоминают другие, преимущество в производительности при запросе один раз, а не в два раза больше ОС. Наконец, аргумент, предложенный, возможно, в пользу второго кода в некоторых случаях - когда разработчик знает среду, в которой работает приложение, - может быть защищен только в специальном случае, когда программа создала частную среду для (и другие экземпляры одной и той же программы).

Даже в этом случае это плохая практика и может привести к длительной бесполезной отладке. Например, тот факт, что мы устанавливаем разрешения для каталога, не должен оставлять нас с разрешениями на показ, которые установлены надлежащим образом для наших целей. Родительский каталог можно установить с другими разрешениями. В общем, программа должна всегда работать правильно, и программисту не следует ожидать какой-либо конкретной среды.




В Python 3.4 вы также можете использовать новый модуль pathlib :

from pathlib import Path
path = Path("/my/directory/filename.txt")
try:
    if not path.parent.exists():
        path.parent.mkdir(parents=True)
except OSError:
    # handle error; you can also catch specific errors like
    # FileExistsError and so on.



Links