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

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

Вступление

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

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

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

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

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

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

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

Допустим, у нас есть абсолютный путь к каталогу, данный нам в виде строки, и мы хотим создать подкаталог с заданным именем. Давайте создадим каталог под названием OuterDirectory и InnerDirectory в него 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() принимает три параметра: mode , parents и exit_ok .

  • Параметр mode , если он задан, в сочетании с umask указывает, какие пользователи имеют права на чтение, запись и выполнение. По умолчанию у всех пользователей есть все привилегии, которые могут быть не теми, которые нам нужны, если безопасность является проблемой. Мы коснемся этого позже.
  • parents указывает, в том случае , если родительский каталог отсутствует, следует метод:
    1. Создайте сам отсутствующий родительский каталог ( true )
    2. Или вызвать ошибку, как в нашем втором примере ( false )
  • 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------rx 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 предлагает отличную поддержку для этого через модуль pathlib

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

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus

Содержание