Обработка путей к файлам и каталогам
Для глубокого погружения в практические операции с файловой системой ознакомьтесь с нашей статьей в блоге: 10 основных операций с файловой системой, которые должен знать каждый разработчик.
В Python есть два основных модуля для работы с путями. Один — это модуль os.path, а другой — модуль pathlib.
Pathlib против модуля OS
pathlib предоставляет гораздо больше функций, чем перечислено выше, например, получение имени файла, получение расширения файла, чтение/запись файла без его ручного открытия и т. д. См. официальную документацию, если хотите узнать больше.
Пути в Linux и Windows
В Windows пути записываются с использованием обратных слешей (\) в качестве разделителя между именами папок. В операционных системах на базе Unix, таких как macOS, Linux и BSD, в качестве разделителя путей используется прямая косая черта (/). Объединение путей может стать головной болью, если ваш код должен работать на разных платформах.
К счастью, модуль Python pathlib предоставляет простой способ справиться с этим.
Использование pathlib в *nix:
# pathlib.Path: кроссплатформенная обработка путей
from pathlib import Path
print(Path('usr').joinpath('bin').joinpath('spam')) # Объединить компоненты пути
usr/bin/spam
pathlib также предоставляет ярлык для joinpath с использованием оператора /:
# Оператор Path (/): удобный способ объединения путей (кроссплатформенный)
from pathlib import Path
print(Path('usr') / 'bin' / 'spam') # Использовать оператор / вместо joinpath()
usr/bin/spam
Обратите внимание, что разделитель путей отличается между Windows и операционными системами на базе Unix, поэтому вам следует использовать pathlib вместо конкатенации строк для объединения путей.
Войдите в систему, чтобы ответить на эту викторину и отслеживать свой прогресс обучения
Path('usr') + 'bin' + 'spam'Path('usr') / 'bin' / 'spam'Path('usr').join('bin').join('spam')Path('usr/bin/spam')Объединение путей полезно, если вам нужно создать разные пути к файлам в одном и том же каталоге.
Использование pathlib в *nix:
# Path.home(): получить домашний каталог пользователя, объединить с именами файлов
my_files = ['accounts.txt', 'details.csv', 'invite.docx']
home = Path.home() # Получить путь к домашнему каталогу
for filename in my_files:
print(home / filename) # Объединить путь к дому с каждым именем файла
/home/labex/project/accounts.txt
/home/labex/project/details.csv
/home/labex/project/invite.docx
Развертывание домашнего каталога пользователя
Использование os.path.expanduser() для развертывания ~ в домашний каталог пользователя:
import os.path
# Развернуть ~ в домашний каталог пользователя
print(os.path.expanduser('~'))
/home/labex/project
# Развернуть ~/Documents в полный путь
print(os.path.expanduser('~/Documents'))
/home/labex/project/Documents
# Работает с путями, содержащими ~
print(os.path.expanduser('~/myfile.txt'))
/home/labex/project/myfile.txt
Текущий рабочий каталог
Вы можете получить текущий рабочий каталог с помощью pathlib:
# Path.cwd(): получить текущий рабочий каталог
from pathlib import Path
print(Path.cwd()) # Возвращает текущий рабочий каталог в виде объекта Path
/home/labex/project
Создание новых папок
Использование pathlib в *nix:
from pathlib import Path
cwd = Path.cwd()
(cwd / 'delicious' / 'walnut' / 'waffles').mkdir()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/pathlib.py", line 1226, in mkdir
self._accessor.mkdir(self, mode)
File "/usr/lib/python3.6/pathlib.py", line 387, in wrapped
return strfunc(str(pathobj), *args)
FileNotFoundError: [Errno 2] No such file or directory: '/home/labex/project/delicious/walnut/waffles'
О нет, мы получили досадную ошибку! Причина в том, что каталога ‘delicious’ не существует, поэтому мы не можем создать каталоги ‘walnut’ и ‘waffles’ внутри него. Чтобы это исправить, сделайте следующее:
# mkdir(parents=True): создать каталог и все родительские каталоги, если необходимо
from pathlib import Path
cwd = Path.cwd()
(cwd / 'delicious' / 'walnut' / 'waffles').mkdir(parents=True) # Создать вложенные каталоги
И все в порядке :)
Абсолютные и относительные пути
Существует два способа указать путь к файлу.
- Абсолютный путь, который всегда начинается с корневой папки
- Относительный путь, который относителен к текущему рабочему каталогу программы
Также существуют папки с точкой (.) и двумя точками (..). Это не настоящие папки, а специальные имена, которые можно использовать в пути. Одна точка (“точка”) для имени папки является сокращением для “текущий каталог”. Две точки (“точка-точка”) означают “родительский каталог”.
Обработка абсолютных путей
Чтобы проверить, является ли путь абсолютным, используя pathlib:
from pathlib import Path
Path('/').is_absolute()
True
Path('..').is_absolute()
False
Войдите в систему, чтобы ответить на эту викторину и отслеживать свой прогресс обучения
Path('/').is_absolute()?TrueFalseNone'/'Вы можете извлечь абсолютный путь с помощью pathlib:
from pathlib import Path
print(Path.cwd())
/home/labex/project
print(Path('..').resolve())
/home
Обработка относительных путей
Вы можете получить относительный путь от начального пути к другому пути с помощью pathlib:
from pathlib import Path
print(Path('/etc/passwd').relative_to('/'))
etc/passwd
Проверка допустимости пути и файла
Проверка существования файла/каталога
Использование pathlib в *nix:
from pathlib import Path
Path('.').exists()
True
Path('setup.py').exists()
True
Path('/etc').exists()
True
Path('nonexistentfile').exists()
False
Проверка, является ли путь файлом
Использование pathlib в *nix:
from pathlib import Path
Path('setup.py').is_file()
True
Path('/home').is_file()
False
Path('nonexistentfile').is_file()
False
Войдите в систему, чтобы ответить на эту викторину и отслеживать свой прогресс обучения
Path('setup.py').is_file(), если setup.py существует?'setup.py'FalseTrueNoneПроверка, является ли путь каталогом
Использование pathlib в *nix:
from pathlib import Path
Path('/').is_dir()
True
Path('setup.py').is_dir()
False
Path('/spam').is_dir()
False
Получение размера файла в байтах
Использование pathlib в *nix:
from pathlib import Path
stat = Path('/bin/python3.6').stat()
print(stat) # stat содержит некоторую другую информацию о файле
os.stat_result(st_mode=33261, st_ino=141087, st_dev=2051, st_nlink=2, st_uid=0,
--snip--
st_gid=0, st_size=10024, st_atime=1517725562, st_mtime=1515119809, st_ctime=1517261276)
print(stat.st_size) # размер в байтах
10024
Перечисление каталогов
Перечисление содержимого каталога с помощью pathlib в *nix:
from pathlib import Path
for f in Path('/usr/bin').iterdir():
print(f)
...
/usr/bin/tiff2rgba
/usr/bin/iconv
/usr/bin/ldd
/usr/bin/cache_restore
/usr/bin/udiskie
/usr/bin/unix2dos
/usr/bin/t1reencode
/usr/bin/epstopdf
/usr/bin/idle3
...
Размеры файлов в каталоге
ПРЕДУПРЕЖДЕНИЕ
Сами каталоги также имеют размер! Поэтому вам может понадобиться проверить, является ли путь файлом или каталогом, используя методы, описанные в предыдущем разделе.
Использование pathlib в *nix:
from pathlib import Path
total_size = 0
for sub_path in Path('/usr/bin').iterdir():
total_size += sub_path.stat().st_size
print(total_size)
1903178911
Копирование файлов и папок
Модуль shutil предоставляет функции для копирования файлов, а также целых папок.
import shutil
shutil.copy('/tmp/spam.txt', '/tmp/delicious')
/tmp/delicious/spam.txt
shutil.copy('/tmp/eggs.txt', '/tmp/delicious/eggs2.txt')
/tmp/delicious/eggs2.txt
Войдите в систему, чтобы ответить на эту викторину и отслеживать свой прогресс обучения
shutil.copy()Path.copy()os.copy()shutil.copytree()В то время как shutil.copy() скопирует один файл, shutil.copytree() скопирует всю папку и каждый содержащийся в ней каталог и файл:
import shutil
shutil.copytree('/tmp/bacon', '/tmp/bacon_backup')
/tmp/bacon_backup
Перемещение и переименование
import shutil
shutil.move('/tmp/bacon.txt', '/tmp/eggs')
/tmp/eggs/bacon.txt
В пути назначения также может быть указано имя файла. В следующем примере исходный файл перемещается и переименовывается:
shutil.move('/tmp/bacon.txt', '/tmp/eggs/new_bacon.txt')
/tmp/eggs/new_bacon.txt
Если папки eggs не существует, то move() переименует bacon.txt в файл с именем eggs:
shutil.move('/tmp/bacon.txt', '/tmp/eggs')
/tmp/eggs
Удаление файлов и папок
- Вызов
Path.unlink()удалит файл по указанному пути. - Вызов
Path.rmdir()удалит папку по указанному пути. Эта папка должна быть пуста от каких-либо файлов или папок. - Вызов
shutil.rmtree(path)удалит папку по указанному пути, а также все содержащиеся в ней файлы и папки.
Войдите в систему, чтобы ответить на эту викторину и отслеживать свой прогресс обучения
Path.rmdir()shutil.rmtree()Path.unlink()os.remove()Обход дерева каталогов
Объект Path имеет метод rglob() для рекурсивной итерации по файлам и каталогам.
from pathlib import Path
p = Path('/tmp/delicious')
for i in p.rglob('*'):
print(i)
/tmp/delicious/cats
/tmp/delicious/walnut
/tmp/delicious/spam.txt
/tmp/delicious/cats/catnames.txt
/tmp/delicious/cats/zophie.jpg
/tmp/delicious/walnut/waffles
/tmp/delicious/walnut/waffles/butter.txt