файлов - Как я могу безопасно создать вложенный каталог в Python?




рекурсивное создание папок в python (17)

Проверьте, существует ли каталог и при необходимости создайте его?

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

if not os.path.exists(d):
    os.makedirs(d)

или если создание каталога подвержено условиям гонки (т. е. если после проверки пути существует что-то еще, возможно, оно уже сделало это) сделайте следующее:

import errno
try:
    os.makedirs(d)
except OSError as exception:
    if exception.errno != errno.EEXIST:
        raise

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

import tempfile

d = tempfile.mkdtemp()

Вот основные сведения из онлайн-документа:

mkdtemp(suffix='', prefix='tmp', dir=None)
    User-callable function to create and return a unique temporary
    directory.  The return value is the pathname of the directory.

    The directory is readable, writable, and searchable only by the
    creating user.

    Caller is responsible for deleting the directory when done with it.

Новое в Python 3.5: pathlib.Path с exist_ok

Есть новый объект Path (начиная с 3.4) с множеством методов, которые нужно использовать с путями - одним из которых является mkdir .

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

Сначала соответствующий импорт:

from pathlib import Path
import tempfile

Нам не нужно иметь дело с os.path.join сейчас - просто присоедините части пути с помощью / :

directory = Path(tempfile.gettempdir()) / 'sodata'

Затем я уверенно гарантирую, что каталог существует - аргумент exist_ok отображается в Python 3.5:

directory.mkdir(exist_ok=True)

Вот соответствующая часть pathlib.Path.mkdir :

Если exist_ok истинно, исключения FileExistsError будут игнорироваться (такое же поведение, как и команда POSIX mkdir -p ), но только в том случае, если последний компонент пути не является существующим файлом без каталога.

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

todays_file = directory / str(datetime.datetime.utcnow().date())
if todays_file.exists():
    logger.info("todays_file exists: " + str(todays_file))
    df = pd.read_json(str(todays_file))

Объекты Path должны быть принудительно привязаны к str перед другими API, которые ожидают, что пути str могут их использовать.

Возможно, Pandas должен быть обновлен, чтобы принимать экземпляры абстрактного базового класса os.PathLike .

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


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

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

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)

В Python3 os.makedirs поддерживает установку exist_ok . Значение по умолчанию - False , что означает, что OSError будет поднят, если целевой каталог уже существует. Установив exist_ok в значение True , OSError (каталог существует) будет проигнорирован и каталог не будет создан.

os.makedirs(path,exist_ok=True)

В Python2 os.makedirs не поддерживает установку exist_ok . Вы можете использовать подход в ответе гейкки-тойвонен :

import os
import errno

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

В 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.

Вы можете использовать os.listdir для этого:

import os
if 'dirName' in os.listdir('parentFolderPath')
    print('Directory Exists')

Вызовите функцию create_dir() в точке входа вашей программы / проекта.

import os

def create_dir(directory):
    if not os.path.exists(directory):
        print('Creating Directory '+directory)
        os.makedirs(directory)

create_dir('Project directory')

Если вы считаете следующее:

os.path.isdir('/tmp/dirname')

означает, что существует каталог (путь) AND - это каталог. Поэтому для меня этот путь делает то, что мне нужно. Поэтому я могу убедиться, что это папка (а не файл) и существует.


Использование 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

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


Начиная с 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 получил флаг exists_ok начиная с python 3.2).


Попробуйте функцию os.path.exists

if not os.path.exists(dir):
    os.mkdir(dir)

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

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

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

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

Проверьте os.makedirs : (Это гарантирует, что полный путь существует.)
Чтобы справиться с тем, что каталог может существовать, поймите OSError. (Если exist_ok False (по умолчанию), OSError возникает, если целевой каталог уже существует.)

import os
try:
    os.makedirs('./path/to/somewhere')
except OSError:
    pass

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

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

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


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

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


Я нашел этот Q / A, и изначально я был озадачен некоторыми неудачами и ошибками, которые я получал. Я работаю в Python 3 (v.3.5 в виртуальной среде Anaconda в системе Arch Linux x86_64).

Рассмотрим эту структуру каталогов:

└── output/         ## dir
   ├── corpus       ## file
   ├── corpus2/     ## dir
   └── subdir/      ## dir

Вот мои эксперименты / заметки, в которых разъясняются вещи:

# ----------------------------------------------------------------------------
# [1] https://.com/questions/273192/how-can-i-create-a-directory-if-it-does-not-exist

import pathlib

""" Notes:
        1.  Include a trailing slash at the end of the directory path
            ("Method 1," below).
        2.  If a subdirectory in your intended path matches an existing file
            with same name, you will get the following error:
            "NotADirectoryError: [Errno 20] Not a directory:" ...
"""
# Uncomment and try each of these "out_dir" paths, singly:

# ----------------------------------------------------------------------------
# METHOD 1:
# Re-running does not overwrite existing directories and files; no errors.

# out_dir = 'output/corpus3'                ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/'               ## works
# out_dir = 'output/corpus3/doc1'           ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/doc1/'          ## works
# out_dir = 'output/corpus3/doc1/doc.txt'   ## no error but no file created (os.makedirs creates dir, not files!  ;-)
# out_dir = 'output/corpus2/tfidf/'         ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/'         ## works
# out_dir = 'output/corpus3/a/b/c/d/'       ## works

# [2] https://docs.python.org/3/library/os.html#os.makedirs

# Uncomment these to run "Method 1":

#directory = os.path.dirname(out_dir)
#os.makedirs(directory, mode=0o777, exist_ok=True)

# ----------------------------------------------------------------------------
# METHOD 2:
# Re-running does not overwrite existing directories and files; no errors.

# out_dir = 'output/corpus3'                ## works
# out_dir = 'output/corpus3/'               ## works
# out_dir = 'output/corpus3/doc1'           ## works
# out_dir = 'output/corpus3/doc1/'          ## works
# out_dir = 'output/corpus3/doc1/doc.txt'   ## no error but creates a .../doc.txt./ dir
# out_dir = 'output/corpus2/tfidf/'         ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/'         ## works
# out_dir = 'output/corpus3/a/b/c/d/'       ## works

# Uncomment these to run "Method 2":

#import os, errno
#try:
#       os.makedirs(out_dir)
#except OSError as e:
#       if e.errno != errno.EEXIST:
#               raise
# ----------------------------------------------------------------------------

Вывод: на мой взгляд, «Способ 2» более надежный.

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

[2] os.makedirs


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

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

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


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

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

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







operating-system