Автор оригинала: Doug Hellmann.
Цель:
Разбирать, строить, тестировать и иным образом работать с именами файлов и пути с использованием объектно-ориентированного API вместо низкоуровневого строковые операции.
Представления пути
pathlib
включает классы для управления путями файловой системы, отформатированные с использованием либо стандарта POSIX, либо синтаксиса Microsoft Windows. Он включает в себя так называемые «чистые» классы, которые работают со строками, но не взаимодействуют с реальной файловой системой, и «конкретные» классы, которые расширяют API для включения операций, отражающих или изменяющих данные в локальной файловой системе.
Чистые классы PurePosixPath
и PureWindowsPath
могут быть созданы и использоваться в любой операционной системе, поскольку они работают только с именами. Чтобы создать экземпляр правильного класса для работы с реальной файловой системой, используйте Path
, чтобы получить либо PosixPath
, либо WindowsPath
, в зависимости от платформы.
Строительные пути
Чтобы создать новый путь, укажите строку в качестве первого аргумента. Это значение имени представляет собой строковое представление объекта пути. Чтобы создать новый путь, ссылающийся на значение относительно существующего пути, используйте оператор /
для расширения пути. Аргументом оператора может быть строка или другой объект пути.
pathlib_operator.py
import pathlib usr pathlib.PurePosixPath('/usr') print(usr) usr_local usr / 'local' print(usr_local) usr_share usr / pathlib.PurePosixPath('share') print(usr_share) root usr / '..' print(root) etc root / '/etc/' print(etc)
Как показывает значение для root
в выходных данных примера, оператор объединяет значения пути в том виде, в каком они заданы, и не нормализует результат, если он содержит ссылку на родительский каталог ".." . Однако, если сегмент начинается с разделителя пути, он интерпретируется как новая «корневая» ссылка так же, как
os.path.join ()
. Лишние разделители пути удаляются из середины значения пути, как в примере etc
здесь.
$ python3 pathlib_operator.py /usr /usr/local /usr/share /usr/.. /etc
Классы конкретных путей включают метод resolve ()
для нормализации пути путем просмотра файловой системы на предмет каталогов и символических ссылок и создания абсолютного пути, на который ссылается имя.
pathlib_resolve.py
import pathlib usr_local pathlib.Path('/usr/local') share usr_local / '..' / 'share' print(share.resolve())
Здесь относительный путь преобразуется в абсолютный путь к /usr/share
. Если входной путь включает символические ссылки, они также расширяются, чтобы разрешенный путь мог ссылаться непосредственно на цель.
$ python3 pathlib_resolve.py /usr/share
Чтобы построить пути, когда сегменты заранее не известны, используйте joinpath ()
, передавая каждый сегмент пути как отдельный аргумент.
pathlib_joinpath.py
import pathlib root pathlib.PurePosixPath('/') subdirs ['usr', 'local'] usr_local root.joinpath(*subdirs) print(usr_local)
Как и в случае с оператором /
, вызов joinpath ()
создает новый экземпляр.
$ python3 pathlib_joinpath.py /usr/local
Учитывая существующий объект пути, легко создать новый с небольшими отличиями, такими как ссылка на другой файл в том же каталоге. Используйте with_name ()
, чтобы создать новый путь, который заменяет часть имени пути другим именем файла. Используйте with_suffix ()
, чтобы создать новый путь, который заменяет расширение имени файла другим значением.
pathlib_from_existing.py
import pathlib ind pathlib.PurePosixPath('source/pathlib/index.rst') print(ind) py ind.with_name('pathlib_from_existing.py') print(py) pyc py.with_suffix('.pyc') print(pyc)
Оба метода возвращают новые объекты, а исходный остается без изменений.
$ python3 pathlib_from_existing.py source/pathlib/index.rst source/pathlib/pathlib_from_existing.py source/pathlib/pathlib_from_existing.pyc
Парсинг путей
У объектов пути есть методы и свойства для извлечения частичных значений из имени. Например, свойство parts
создает последовательность сегментов пути, анализируемых на основе значения разделителя пути.
pathlib_parts.py
import pathlib p pathlib.PurePosixPath('/usr/local') print(p.parts)
Последовательность представляет собой кортеж, отражающий неизменность экземпляра пути.
$ python3 pathlib_parts.py ('/', 'usr', 'local')
Есть два способа перейти «вверх» по иерархии файловой системы от заданного объекта пути. Свойство parent
относится к новому экземпляру пути для каталога, содержащего путь, значение, возвращаемое os.path.dirname ()
. Свойство parent
– это итерация, которая создает ссылки на родительские каталоги, непрерывно поднимаясь «вверх» по иерархии путей до достижения корня.
pathlib_parents.py
import pathlib p pathlib.PurePosixPath('/usr/local/lib') print('parent: {}'.format(p.parent)) print('\nhierarchy:') for up in p.parents: print(up)
В примере выполняется итерация по свойству parent
и выводятся значения элементов.
$ python3 pathlib_parents.py parent: /usr/local hierarchy: /usr/local /usr /
К другим частям пути можно получить доступ через свойства объекта пути. Свойство name
содержит последнюю часть пути после последнего разделителя пути (то же значение, что и os.path.basename ()
). Свойство суффикс
содержит значение после разделителя расширения, а свойство stem
содержит часть имени перед суффиксом.
pathlib_name.py
import pathlib p pathlib.PurePosixPath('./source/pathlib/pathlib_name.py') print('path : {}'.format(p)) print('name : {}'.format(p.name)) print('suffix: {}'.format(p.suffix)) print('stem : {}'.format(p.stem))
Хотя значения suffix
и stem
аналогичны значениям, создаваемым os.path.splitext ()
, значения основаны только на значении name
, а не полный путь.
$ python3 pathlib_name.py path : source/pathlib/pathlib_name.py name : pathlib_name.py suffix: .py stem : pathlib_name
Создание бетонных дорожек
Экземпляры конкретного класса Path
могут быть созданы из строковых аргументов, относящихся к имени (или потенциальному имени) файла, каталога или символической ссылки в файловой системе. Класс также предоставляет несколько удобных методов для создания экземпляров с использованием часто используемых мест, которые меняются, таких как текущий рабочий каталог и домашний каталог пользователя.
pathlib_convenience.py
import pathlib home pathlib.Path.home() print('home: ', home) cwd pathlib.Path.cwd() print('cwd : ', cwd)
Оба метода создают экземпляры Path
, предварительно заполненные абсолютной ссылкой на файловую систему.
$ python3 pathlib_convenience.py home: /Users/dhellmann cwd : /Users/dhellmann/PyMOTW
Содержание каталога
Есть три метода доступа к спискам каталогов, чтобы узнать имена файлов, доступных в файловой системе. iterdir ()
– это генератор, создающий новый экземпляр Path
для каждого элемента в содержащем каталоге.
pathlib_iterdir.py
import pathlib p pathlib.Path('.') for f in p.iterdir(): print(f)
Если Path
не ссылается на каталог, iterdir ()
вызывает NotADirectoryError
.
$ python3 pathlib_iterdir.py example_link index.rst pathlib_chmod.py pathlib_convenience.py pathlib_from_existing.py pathlib_glob.py pathlib_iterdir.py pathlib_joinpath.py pathlib_mkdir.py pathlib_name.py pathlib_operator.py pathlib_ownership.py pathlib_parents.py pathlib_parts.py pathlib_read_write.py pathlib_resolve.py pathlib_rglob.py pathlib_rmdir.py pathlib_stat.py pathlib_symlink_to.py pathlib_touch.py pathlib_types.py pathlib_unlink.py
Используйте glob ()
, чтобы найти только файлы, соответствующие шаблону.
pathlib_glob.py
import pathlib p pathlib.Path('..') for f in p.glob('*.rst'): print(f)
В этом примере показаны все входные файлы reStructuredText в родительском каталоге сценария.
$ python3 pathlib_glob.py ../about.rst ../algorithm_tools.rst ../book.rst ../compression.rst ../concurrency.rst ../cryptographic.rst ../data_structures.rst ../dates.rst ../dev_tools.rst ../email.rst ../file_access.rst ../frameworks.rst ../i18n.rst ../importing.rst ../index.rst ../internet_protocols.rst ../language.rst ../networking.rst ../numeric.rst ../persistence.rst ../porting_notes.rst ../runtime_services.rst ../text.rst ../third_party.rst ../unix.rst
Процессор glob поддерживает рекурсивное сканирование с использованием префикса шаблона **
или путем вызова rglob ()
вместо glob ()
.
pathlib_rglob.py
import pathlib p pathlib.Path('..') for f in p.rglob('pathlib_*.py'): print(f)
Поскольку этот пример начинается с родительского каталога, необходим рекурсивный поиск, чтобы найти файлы примеров, соответствующие pathlib _ *. Py
.
$ python3 pathlib_rglob.py ../pathlib/pathlib_chmod.py ../pathlib/pathlib_convenience.py ../pathlib/pathlib_from_existing.py ../pathlib/pathlib_glob.py ../pathlib/pathlib_iterdir.py ../pathlib/pathlib_joinpath.py ../pathlib/pathlib_mkdir.py ../pathlib/pathlib_name.py ../pathlib/pathlib_operator.py ../pathlib/pathlib_ownership.py ../pathlib/pathlib_parents.py ../pathlib/pathlib_parts.py ../pathlib/pathlib_read_write.py ../pathlib/pathlib_resolve.py ../pathlib/pathlib_rglob.py ../pathlib/pathlib_rmdir.py ../pathlib/pathlib_stat.py ../pathlib/pathlib_symlink_to.py ../pathlib/pathlib_touch.py ../pathlib/pathlib_types.py ../pathlib/pathlib_unlink.py
Чтение и запись файлов
Каждый экземпляр Path
включает методы для работы с содержимым файла, на который он ссылается. Для немедленного получения содержимого используйте read_bytes ()
или read_text ()
. Для записи в файл используйте write_bytes ()
или write_text ()
. Используйте метод open ()
, чтобы открыть файл и сохранить дескриптор файла, вместо передачи имени встроенной функции open ()
.
pathlib_read_write.py
import pathlib f pathlib.Path('example.txt') f.write_bytes('This is the content'.encode('utf-8')) with f.open('r', encoding'utf-8') as handle: print('read from open(): {!r}'.format(handle.read())) print('read_text(): {!r}'.format(f.read_text('utf-8')))
Удобные методы выполняют некоторую проверку типов перед открытием файла и записью в него, но в остальном они эквивалентны выполнению операции напрямую.
$ python3 pathlib_read_write.py read from open(): 'This is the content' read_text(): 'This is the content'
Управление каталогами и символическими ссылками
Пути, представляющие каталоги или символические ссылки, которые не существуют, могут использоваться для создания связанных записей файловой системы.
pathlib_mkdir.py
import pathlib p pathlib.Path('example_dir') print('Creating {}'.format(p)) p.mkdir()
Если путь уже существует, mkdir ()
вызывает FileExistsError
.
$ python3 pathlib_mkdir.py Creating example_dir $ python3 pathlib_mkdir.py Creating example_dir Traceback (most recent call last): File "pathlib_mkdir.py", line 16, inp.mkdir() File ".../lib/python3.6/pathlib.py", line 1226, in mkdir self._accessor.mkdir(self, mode) File ".../lib/python3.6/pathlib.py", line 387, in wrapped return strfunc(str(pathobj), *args) FileExistsError: [Errno 17] File exists: 'example_dir'
Используйте symlink_to ()
, чтобы создать символическую ссылку. Ссылка будет названа на основе значения пути и будет ссылаться на имя, указанное в качестве аргумента для symlink_to ()
.
pathlib_symlink_to.py
import pathlib p pathlib.Path('example_link') p.symlink_to('index.rst') print(p) print(p.resolve().name)
В этом примере создается символическая ссылка, затем используется resolve ()
для чтения ссылки, чтобы найти то, на что она указывает, и распечатать имя.
$ python3 pathlib_symlink_to.py example_link index.rst
Типы файлов
Экземпляр Path
включает несколько методов для проверки типа файла, на который ссылается путь. В этом примере создается несколько файлов разных типов и проверяется их, а также несколько других файлов для конкретных устройств, доступных в локальной операционной системе.
pathlib_types.py
import itertools import os import pathlib root pathlib.Path('test_files') # Clean up from previous runs. if root.exists(): for f in root.iterdir(): f.unlink() else: root.mkdir() # Create test files (root / 'file').write_text( 'This is a regular file', encoding'utf-8') (root / 'symlink').symlink_to('file') os.mkfifo(str(root / 'fifo')) # Check the file types to_scan itertools.chain( root.iterdir(), [pathlib.Path('/dev/disk0'), pathlib.Path('/dev/console')], ) hfmt '{:18s}' + (' {:>5}' * 6) print(hfmt.format('Name', 'File', 'Dir', 'Link', 'FIFO', 'Block', 'Character')) print() fmt '{:20s} ' + ('{!r:>5} ' * 6) for f in to_scan: print(fmt.format( str(f), f.is_file(), f.is_dir(), f.is_symlink(), f.is_fifo(), f.is_block_device(), f.is_char_device(), ))
Каждый из методов, is_dir ()
, is_file ()
, is_symlink ()
, is_socket ()
, < code> is_fifo () , is_block_device ()
и is_char_device ()
не принимает аргументов.
$ python3 pathlib_types.py Name File Dir Link FIFO Block Character test_files/fifo False False False True False False test_files/file True False False False False False test_files/symlink True False True False False False /dev/disk0 False False False False True False /dev/console False False False False False True
Свойства файла
Подробную информацию о файле можно получить с помощью методов stat ()
или lstat ()
(для проверки статуса чего-то, что может быть символической ссылкой). Эти методы дают те же результаты, что и os.stat ()
и os.lstat ()
.
pathlib_stat.py
import pathlib import sys import time if len(sys.argv) 1: filename __file__ else: filename sys.argv[1] p pathlib.Path(filename) stat_info p.stat() print('{}:'.format(filename)) print(' Size:', stat_info.st_size) print(' Permissions:', oct(stat_info.st_mode)) print(' Owner:', stat_info.st_uid) print(' Device:', stat_info.st_dev) print(' Created :', time.ctime(stat_info.st_ctime)) print(' Last modified:', time.ctime(stat_info.st_mtime)) print(' Last accessed:', time.ctime(stat_info.st_atime))
Результат будет зависеть от того, как был установлен пример кода. Попробуйте передать в pathlib_stat.py
другие имена файлов в командной строке.
$ python3 pathlib_stat.py pathlib_stat.py: Size: 607 Permissions: 0o100644 Owner: 527 Device: 16777220 Created : Thu Dec 29 12:38:23 2016 Last modified: Thu Dec 29 12:38:23 2016 Last accessed: Sun Mar 18 16:21:41 2018 $ python3 pathlib_stat.py index.rst index.rst: Size: 19569 Permissions: 0o100644 Owner: 527 Device: 16777220 Created : Sun Mar 18 16:11:31 2018 Last modified: Sun Mar 18 16:11:31 2018 Last accessed: Sun Mar 18 16:21:40 2018
Для упрощения доступа к информации о владельце файла используйте owner ()
и group ()
.
pathlib_ownership.py
import pathlib p pathlib.Path(__file__) print('{} is owned by {}/{}'.format(p, p.owner(), p.group()))
Хотя stat ()
возвращает числовые значения идентификатора системы, эти методы ищут имя, связанное с идентификаторами.
$ python3 pathlib_ownership.py pathlib_ownership.py is owned by dhellmann/dhellmann
Метод touch ()
работает так же, как команда Unix touch
для создания файла или обновления времени модификации и разрешений существующего файла.
pathlib_touch.py
import pathlib import time p pathlib.Path('touched') if p.exists(): print('already exists') else: print('creating new') p.touch() start p.stat() time.sleep(1) p.touch() end p.stat() print('Start:', time.ctime(start.st_mtime)) print('End :', time.ctime(end.st_mtime))
Выполнение этого примера более одного раза обновляет существующий файл при последующих запусках.
$ python3 pathlib_touch.py creating new Start: Sun Mar 18 16:21:41 2018 End : Sun Mar 18 16:21:42 2018 $ python3 pathlib_touch.py already exists Start: Sun Mar 18 16:21:42 2018 End : Sun Mar 18 16:21:43 2018
Разрешения
В Unix-подобных системах права доступа к файлам можно изменить с помощью chmod ()
, передав режим как целое число. Значения режима могут быть созданы с использованием констант, определенных в модуле stat
. В этом примере переключается бит разрешения пользователя на выполнение.
pathlib_chmod.py
import os import pathlib import stat # Create a fresh test file. f pathlib.Path('pathlib_chmod_example.txt') if f.exists(): f.unlink() f.write_text('contents') # Determine what permissions are already set using stat. existing_permissions stat.S_IMODE(f.stat().st_mode) print('Before: {:o}'.format(existing_permissions)) # Decide which way to toggle them. if not (existing_permissions & os.X_OK): print('Adding execute permission') new_permissions existing_permissions | stat.S_IXUSR else: print('Removing execute permission') # use xor to remove the user execute permission new_permissions existing_permissions ^ stat.S_IXUSR # Make the change and show the new value. f.chmod(new_permissions) after_permissions stat.S_IMODE(f.stat().st_mode) print('After: {:o}'.format(after_permissions))
Сценарий предполагает, что у него есть разрешения, необходимые для изменения режима файла при запуске.
$ python3 pathlib_chmod.py Before: 644 Adding execute permission After: 744
Удаление
В зависимости от типа есть два метода удаления файлов из файловой системы. Чтобы удалить пустой каталог, используйте rmdir ()
.
pathlib_rmdir.py
import pathlib p pathlib.Path('example_dir') print('Removing {}'.format(p)) p.rmdir()
Исключение FileNotFoundError
возникает, если пост-условия уже выполнены, а каталог не существует. Также ошибкой является попытка удалить каталог, который не пуст.
$ python3 pathlib_rmdir.py Removing example_dir $ python3 pathlib_rmdir.py Removing example_dir Traceback (most recent call last): File "pathlib_rmdir.py", line 16, inp.rmdir() File ".../lib/python3.6/pathlib.py", line 1270, in rmdir self._accessor.rmdir(self) File ".../lib/python3.6/pathlib.py", line 387, in wrapped return strfunc(str(pathobj), *args) FileNotFoundError: [Errno 2] No such file or directory: 'example_dir'
Для файлов, символических ссылок и большинства других типов путей используйте unlink ()
.
pathlib_unlink.py
import pathlib p pathlib.Path('touched') p.touch() print('exists before removing:', p.exists()) p.unlink() print('exists after removing:', p.exists())
У пользователя должно быть разрешение на удаление файла, символической ссылки, сокета или другого объекта файловой системы.
$ python3 pathlib_unlink.py exists before removing: True exists after removing: False
Смотрите также
- стандартная библиотечная документация для pathlib
- os.path – Платформенно-независимые манипуляции с именами файлов
- Управление разрешениями файловой системы – обсуждение
os.stat ()
иos.lstat ()
. - glob – сопоставление шаблонов оболочки Unix для имен файлов
- PEP 428 – модуль pathlib