DevGang
Авторизоваться

Python: безопасное создание вложенного каталога 

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

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

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

В этой статье мы увидим, как создать подкаталог в Python безопасным способом, шаг за шагом.

Безопасное создание вложенного каталога с помощью pathlib

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

Благодаря этому ваш код должен быть независимым от платформы. Обратите внимание, что это работает только в более новых версиях Python (3.5 и выше).

Допустим, у нас есть абсолютный путь к каталогу, данный нам в виде строки, и мы хотим создать подкаталог с заданным именем. Давайте создадим каталог с именем OuterDirectory и поместим в него InnerDirectory.

Мы импортируем Path из модуля pathlib, создадим объект Path с желаемым путем для нашего нового файла и воспользуемся методом mkdir(), имеющим следующую сигнатуру:

Path.mkdir(mode=0o777, parents=False, exist_ok=False)

Следующий фрагмент кода выполняет то, что мы описали выше:

from pathlib import Path # Import the module
path = Path("/home/kristina/OuterDirectory/InnerDirectory") # Create Path object
path.mkdir() # Cake the directory

В случае неудачи mkdir() каталог не будет создан и возникнет ошибка.

Параметры и ошибки mkdir()

Если вы запустите код без создания OuterDirectory, вы увидите следующую ошибку:

Traceback (most recent call last):
  File "makesubdir.py", line 3, in <module>
    path.mkdir()
  File "/home/kristina/anaconda3/lib/python3.7/pathlib.py", line 1230, in mkdir
    self._accessor.mkdir(self, mode)
FileNotFoundError: [Errno 2] No such file or directory: '/home/kristina/OuterDirectory/InnerDirectory'

Или, если InnerDirectory уже существует:

Traceback (most recent call last):
  File "/home/kristina/Desktop/UNM/makesubdir.py", line 3, in <module>
    path.mkdir()
  File "/home/kristina/anaconda3/lib/python3.7/pathlib.py", line 1230, in mkdir
    self._accessor.mkdir(self, mode)
FileExistsError: [Errno 17] File exists: '/home/kristina/OuterDirectory/InnerDirectory'

Если каталог уже существует, возникнет ошибка FileExistsError, а если родительский каталог не существует, будет вызвано FileNotFoundError.

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

from pathlib import Path 
path = Path("/home/kristina/OuterDirectory/InnerDir") 
try:
    path.mkdir() 
except OSError:
    print("Failed to make nested directory")
else:
    print("Nested directory made")

При запуске, если каталог успешно создан, вывод будет:

Nested directory made

Если мы столкнемся с ошибками, будет выведено следующее:

Failed to make a nested directory

Метод mkdir() принимает три параметра: modeparents, и exit_ok.

  1. Параметр mode, если он задан, в сочетании с umask указывает, какие пользователи имеют права на чтение, запись и выполнение. По умолчанию все пользователи имеют все привилегии, которые могут быть не тем, что нам нужно, если речь идет о безопасности. Мы еще поговорим об этом позже.
  2. parents указывает, что в случае отсутствия родительского каталога, должен ли метод:Создайте сам отсутствующий родительский каталог (true)Или вызвать ошибку, как в нашем втором примере (false)
  3. exist_ok указывает, следует ли вызывать FileExistsError, если каталог с таким же именем уже существует. Обратите внимание, что эта ошибка все равно будет возникать, если файл с тем же именем не является каталогом.

Назначение прав доступа

Давайте создадим каталог с именем SecondInnerDirectory, в котором только владелец имеет все права на чтение, запись и выполнение, внутри несуществующего SecondOuterDirectory:

from pathlib import Path
path = Path("/home/kristina/SecondOuterDirectory/SecondInnerDirectory")
path.mkdir(mode = 0o007, parents= True, exist_ok= True)

Это должно выполняться без ошибок. Если мы перейдем к SecondOuterDirectory и проверим его содержимое с консоли следующим образом:

ls -al

У нас должен получиться результат:

total 12
drwxrwxr-x  3 kristina kristina 4096 dec 10 01:26 .
drwxr-xr-x 77 kristina kristina 4096 dec 10 01:26 ..
d------r-x  2 kristina kristina 4096 dec 10 01:26 SecondInnerDirectory

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

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

Давайте перепишем наш код, чтобы проверить это:

from pathlib import Path
import os 

old_mask = os.umask(0) # Saving the old umask value and setting umask to 0

path = Path("/home/kristina/SecondOuterDirectory/SecondInnerDirectory")
path.mkdir(mode = 0o007, parents= True, exist_ok= True)

os.umask(old_mask) # Reverting umask value

Выполнение этого кода и повторное использование команды ls -al приведет к следующему результату:

total 12
drwxrwxrwx  3 kristina kristina 4096 dec 10 01:45 . 
drwxr-xr-x 77 kristina kristina 4096 dec 10 01:45 ..
d------rwx  2 kristina kristina 4096 dec 10 01:45 SecondInnerDirectory

Источник:

#Python
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

Поделитесь своим опытом, расскажите о новом инструменте, библиотеке или фреймворке. Для этого не обязательно становится постоянным автором.

Попробовать

Оплатив хостинг 25$ в подарок вы получите 100$ на счет

Получить