4.2 Работа с файловой системой#
Определение пути#
Помимо импортов функций и переменных из других файлов также часто придется взаимодействовать с файловой системой для чтения данных. Ключевым моментом при работе с файловой системой будет определение пути к файлу.
Путь может быть либо абсолютным, либо относительным. Абсолютный путь является полным путем от корневого каталога, относительный - от текущего рабочего каталога.
Приведем несколько примеров. Для этого сначала представим, что у нас есть следующая файловая структура:
C:\
└── folder\
├── data.txt
└── subfolder\
├── file.txt
├── example.py
└── one_more_subfolder\
└── one_more_file.txt
Если мы исполним файл example.py, то текущей рабочей директорией будет C:\folder\subfolder
Чтобы из исполняемого файла example.py обратиться к file.txt, мы можем указать один из следующих путей:
absolute_path = 'C:\folder\subfolder\file.txt'
relative_path = 'file.txt'
Чтобы обратиться к файлу one_more_file.txt:
absolute_path = 'C:\folder\subfolder\one_more_subfolder\file.txt'
relative_path = 'one_more_subfolder/file.txt'
Чтобы обратиться к файлу data.txt:
absolute_path = 'C:\folder\data.txt'
relative_path = '../data.txt' # .. обозначает, что нужно вернуться на директорию выше
Операции с путями#
Понимая, как устроены пути и какой путь является точкой вызова - текущей директорией, легко прописать путь к файлу в виде текстовой переменной. Некоторые сложности могут возникнуть, когда путь определяется в результате выражения и складывается из нескольких частей. Проблема заключается в том, что на разных операционных системах пути записываются несколько по-разному и где-то используется \ для разделения директорий, а где-то /. Чтобы не задумываться о том, как правильно реализовать сложение таких путей, можно воспользоваться модулем os.path, конкретно функцией join из него.
join - принимает на вход строковые позиционные аргументы, которые он будет объединять между собой, как будто это перечень директорий в пути
from os import path
my_path = path.join('path', 'to', 'my', 'folder')
my_path
'path/to/my/folder'
Помимо задачи объединения пути из составляющих, os.path также может решать обратную задачу и возвращать составляющие пути. Так, две функции, к которым часто придется обращаться:
basename- возвращает имя последней директории в пути (или имя файла)dirname- возвращает путь до последней директории в пути (или до имени файла)
path.basename(my_path)
'folder'
path.dirname(my_path)
'path/to/my'
C помощью функции exists можно проверить, существует ли указанный путь:
path.exists(my_path)
False
А с помощью функций isdir, isfile и подобных можно узнать, указывает ли путь на файл, директорию или что-то другое
path.isdir(my_path)
False
path.isfile(my_path)
False
Еще одной важной функцией, на которую мы обратим внимание, будет функция os.listdir. Она уже не относится к модулю path, но также входит в os и позволяет взаимодействовать с файловой системой, возвращая список файлов и директорий по указанному пути:
from os import listdir
listdir('./') # Получим все содержимое текущей директории
['intro.md',
'20.io.files.ipynb',
'19.filesystem.ipynb',
'data',
'21.json.ipynb',
'18.modules.ipynb']
Модуль Pathlib#
Недостатком модуля os.path является то, что это набор отдельных функций, которые вызываются для отдельных строковых переменных. Развитием идеи модуля os.path стал модуль Pathlib, который добавляет новый класс объектов Path, и все дальнейшие функции вызываются как методы объекта.
from pathlib import Path
my_path = Path('path/to/my/folder')
my_path
PosixPath('path/to/my/folder')
Для объединения путей Path предлагает выполнять отдельную операцию сложения, которая использует оператор деления /
path_part_1 = Path('path/to')
path_part_2 = Path('my/folder')
file = 'example.txt'
path = path_part_1 / path_part_2 / file
path
PosixPath('path/to/my/folder/example.txt')
Доступ к отдельным составляющим пути работает, напоминая os.path, но с некоторыми изменениями:
path.name # Вместо os.basename достаточно обратиться к атрибуту name
'example.txt'
path.parent # Вместо os.dirname достаточно обратиться к атрибуту parent
PosixPath('path/to/my/folder')
path.exists() # exists также проверяет существует ли путь
False
path.is_dir() # is_dir является ли путь путем до директории
False
path.is_file() # is_dir является ли путь путем до файла
False
is_dir и is_file, как и в аналогичных функциях в os.path, возвращают True, только если путь существует.
Среди прочего Path позволяет получать список директорий по пути и выполнять много других функций от поиска до создания файлов, что регулярно встречается в реальных практических задачах. С полным функционалом можно ознакомиться в документации.
path = Path('./')
list(path.iterdir())
[PosixPath('intro.md'),
PosixPath('20.io.files.ipynb'),
PosixPath('19.filesystem.ipynb'),
PosixPath('data'),
PosixPath('21.json.ipynb'),
PosixPath('18.modules.ipynb')]
Обход вложенных директорий
Для обхода вложенных директорий существует функция os.walk. Она работает как итератор, совершая обход по всем директориям для указанного пути, возвращая на каждом шагу отдельно текущую директория обхода, список файлов в ней и список других директорий в ней.