Автор оригинала: Kristina Popovic.
Вступление
Манипулирование файлами-один из самых важных навыков, которым нужно овладеть в любом языке программирования, и делать это правильно крайне важно. Ошибка может вызвать проблему в вашей программе, других программах, работающих в той же системе, и даже в самой системе.
Возможные ошибки могут возникнуть из-за того, что родительский каталог не существует, или из-за того, что другие программы одновременно изменяют файлы в файловой системе, создавая то, что называется race condition .
Условие race (в данном случае называемое data race ) возникает, когда две или более программы хотят создать файл с одинаковым именем в одном и том же месте. Если этот тип ошибки возникает, его очень трудно найти и исправить, так как он недетерминирован, или, проще говоря, разные вещи могут произойти в зависимости от точного времени двух гонщиков, конкурирующих за данные.
В этой статье мы рассмотрим, как создать подкаталог в Python the safeway, шаг за шагом. Отныне все будет работать на Mac, Linux и Windows.
Безопасное создание вложенного каталога с помощью path lib
Существует множество способов создания подкаталога, но, возможно, самым простым является использование модуля pathlib
. Модуль pathlib
в первую очередь предназначен для абстрагирования различных файловых систем операционной системы и обеспечения единого интерфейса для работы с большинством из них.
Благодаря этому ваш код должен быть независимым от платформы. Обратите внимание, что это работает только на более новых версиях Python (3.5 и выше).
Допустим, у нас есть абсолютный путь к каталогу, заданный нам в виде строки, и мы хотим создать подкаталог с заданным именем. Давайте создадим каталог с именем Outer Directory
и поместим в него Inner Directory
.
Мы импортируем 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()
Если вы запустите код без создания внешнего каталога , то увидите следующую ошибку:
Traceback (most recent call last): File "makesubdir.py", line 3, inpath.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'
Или если Внутренний каталог
уже существует:
Traceback (most recent call last): File "/home/kristina/Desktop/UNM/makesubdir.py", line 3, inpath.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
указывает, что в случае отсутствия родительского каталога метод должен:- Создайте сам отсутствующий родительский каталог (
true
) - Или вызвать ошибку, как в нашем втором примере (
false
)
- Создайте сам отсутствующий родительский каталог (
exist_ok
указывает, если файлСуществует Ошибка
должна быть вызвана, если каталог с таким же именем уже существует. Обратите внимание, что эта ошибка все равно будет вызвана, если файл с тем же именем не является каталогом.
Назначение Прав Доступа
Давайте создадим каталог с именем Second Inner Directory
, где только владелец имеет все права на чтение, запись и выполнение, внутри несуществующего SecondOuterDirectory
:
from pathlib import Path path = Path("/home/kristina/SecondOuterDirectory/SecondInnerDirectory") path.mkdir(mode = 0o007, parents= True, exist_ok= True)
Это должно выполняться без ошибок. Если мы перейдем во Второй внешний каталог и проверим его содержимое с консоли следующим образом:
$ 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()
из модуля OS. 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
.
Ошибки всегда могут возникать при работе с файловыми системами, и лучший способ справиться с этим-тщательно настроить системы, чтобы поймать все ошибки, которые потенциально могут привести к сбою нашей программы или вызвать другие проблемы. Написание чистого кода делает программы долговечными.