Вопрос-Ответ

How do I create a directory, and any missing parent directories?

Как мне создать каталог и все отсутствующие родительские каталоги?

Как мне создать каталог по заданному пути, а также создать все отсутствующие родительские каталоги по этому пути? Например, команда Bash mkdir -p /path/to/nested/directory делает это.

Переведено автоматически
Ответ 1

На Python ≥ 3.5 используйте pathlib.Path.mkdir:

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

Для более старых версий Python я вижу два ответа с хорошими качествами, каждый с небольшим недостатком, поэтому я выскажу свое мнение по этому поводу:

Попробуйте os.path.exists и подумайте os.makedirs о создании.

import os
if not os.path.exists(directory):
os.makedirs(directory)

Как отмечалось в комментариях и в других местах, существует условие гонки – если каталог создается между вызовами os.path.exists и os.makedirs, то os.makedirs произойдет сбой с помощью OSError. К сожалению, полный перехват OSError и продолжение не является надежным способом, поскольку он проигнорирует сбой при создании каталога из-за других факторов, таких как недостаточные разрешения, переполненный диск и т.д.

Одним из вариантов было бы перехватить OSError и изучить встроенный код ошибки (см. Существует ли кроссплатформенный способ получения информации из OSError в Python):

import os, errno

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

В качестве альтернативы может быть второй os.path.exists, но предположим, что другой создал каталог после первой проверки, а затем удалил его перед второй – нас все равно можно обмануть.

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

Современные версии Python значительно улучшают этот код, как за счет раскрытия FileExistsError (в версии 3.3+)...

try:
os.makedirs("path/to/directory")
except FileExistsError:
# directory already exists
pass

...и позволив ключевое слово аргумент os.makedirs называется exist_ok (в 3.2+).

os.makedirs("path/to/directory", exist_ok=True)  # succeeds even if directory exists.
Ответ 2

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, в нем отсутствует полезная exist_ok опция. Бэкпорт предназначен для предложения более новой и превосходной реализации 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, создается как для файлов, так и для каталогов. Надежнее просто проверить, существует ли каталог.

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

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

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

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


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

Ответ 3

Использование try except и правильного кода ошибки из модуля errno устраняет состояние гонки и является кроссплатформенным:

import os
import errno

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

Другими словами, мы пытаемся создать каталоги, но если они уже существуют, мы игнорируем ошибку. С другой стороны, сообщается о любой другой ошибке. Например, если вы заранее создадите каталог 'a' и удалите из него все разрешения, вы получите OSError запрос с errno.EACCES (в разрешении отказано, ошибка 13).

Ответ 4

Начиная с Python 3.5, pathlib.Path.mkdir имеет exist_ok флаг:

from pathlib import Path
path = Path('/my/directory/filename.txt')
path.parent.mkdir(parents=True, exist_ok=True)
# path.parent ~ os.path.dirname(path)

Это рекурсивно создает каталог и не вызывает исключения, если каталог уже существует.

(так же, как os.makedirs получил exist_ok флаг, начиная с python 3.2, например, os.makedirs(path, exist_ok=True))


Примечание: когда я публиковал этот ответ, ни один из других ответов не упоминался exist_ok...

2023-06-20 09:07 python