Управление путями файловой системы Python 3 с помощью модуля pathlib
28 октября, 2020 12:30 пп 1 819 views | Комментариев нетDevelopment, Python | Amber | Комментировать запись
Python 3 включает модуль pathlib для управления путями файловой системы независимо от операционной системы. Модуль pathlib похож на os.path, но pathlib предлагает интерфейс более высокого уровня и часто в разы удобнее, чем os.path.
Файлы на компьютере можно идентифицировать с помощью иерархических путей. Например, мы можем идентифицировать файл wave.txt на компьютере по этому пути:
/Users/planetearth/ocean/wave.txt
Операционные системы представляют пути немного по-разному. Windows может представлять путь к файлу wave.txt как C:\Users\planetearth\ocean\wave.txt
.
Модуль pathlib будет вам полезен, если в вашей программе Python вы создаете или перемещаете файлы в файловой системе, запрашиваете списки файлов, которые соответствуют заданному расширению или шаблону, или создаете подходящие для операционной системы пути к файлам на основе коллекций необработанных строк.
В этом мануале мы рассмотрим несколько способов использования модуля pathlib для представления и управления путями файловой системы.
Требования
Чтобы получить максимальную пользу от этого мануала, рекомендуем сначала изучить основы программирования на Python 3. Вы можете найти полезную информацию о Python 3 здесь.
Создание класса Path
Модуль pathlib предоставляет несколько классов, но одним из наиболее важных является класс Path. Экземпляры класса Path отображают путь к файлу или каталогу в файловой системе компьютера.
Например, следующий код создает экземпляр Path, представляющий часть пути к файлу wave.txt:
from pathlib import Path
wave = Path("ocean", "wave.txt")
print(wave)
Если мы запустим этот код, мы получим следующий результат:
ocean/wave. txt
from pathlib import Path делает класс Path доступным для программы. Затем Path (“ocean”, “wave.txt”) создает новый экземпляр Path. Вывод показывает, что Python добавил соответствующий разделитель операционной системы (/) между двумя компонентами пути, которые мы ему задали: «ocean» и «wave.txt».
Примечание: В зависимости от операционной системы ваш результат может несущественно отличаться от результатов, показанных в этом руководстве. Например, если вы работаете в Windows, в данном случае вы получите ocean\wave.txt.
В настоящее время объект Path, присвоенный переменной wave, содержит относительный путь. Другими словами, файл ocean/wave.txt может существовать в нескольких местах нашей файловой системы. Например, он может находиться в /Users/user_1/ocean/wave.txt или в /Users/user_2/research/ocean/wave.txt – мы не указали, какой именно из этих файлов мы имеем в виду. Абсолютный путь – это путь, который относится к одному расположению в файловой системе.
Вы можете использовать Path.home(), чтобы получить абсолютный путь к домашнему каталогу текущего пользователя:
home = Path.home()
wave_absolute = Path(home, "ocean", "wave.txt")
print(home)
print(wave_absolute)
Если мы запустим этот код, мы получим примерно следующий результат:
/Users/planetearth
/Users/planetearth/ocean/wave.txt
Примечание: Как упоминалось ранее, результат будет зависеть от вашей операционной системы. Ваш домашний каталог, конечно, также будет отличаться от нашего условного /Users/planetearth.
Path.home() возвращает экземпляр Path с абсолютным путем к домашнему каталогу текущего пользователя. Затем мы передаем этот экземпляр Path и строки «ocean» и «wave.txt» в другой конструктор Path, чтобы создать абсолютный путь к файлу wave.txt. Выходные данные показывают, что первая строка – это домашний каталог, а вторая – это домашний каталог плюс ocean/wave.txt.
Этот пример также иллюстрирует важную особенность класса Path: конструктор Path принимает как строки, так и уже существующие объекты Path.
Давайте более внимательно рассмотрим поддержку строк и объектов Path в конструкторе Path:
shark = Path(Path.home(), "ocean", "animals", Path("fish", "shark.txt"))
print(shark)
Если мы запустим этот код, мы получим такой вывод:
/Users/planetearth/ocean/animals/fish/shark.txt
shark – это путь к файлу, который мы создали, используя объекты Path (Path.home() и Path(“fish”, “shark.txt”)). Конструктор Path обрабатывает оба типа объектов и аккуратно объединяет их, используя соответствующий разделитель операционной системы, в данном случае /.
Доступ к атрибутам файла
Теперь, когда вы научились создавать экземпляры Path, давайте посмотрим, как использовать эти экземпляры для доступа к информации о файле.
Мы можем использовать атрибуты name и suffix для доступа к именам и суффиксам файлов:
wave = Path("ocean", "wave.txt")
print(wave)
print(wave.name)
print(wave.suffix)
Запустив этот код, мы получим следующий результат:
/Users/planetearth/ocean/wave. txt
wave.txt
.txt
Этот вывод показывает, что имя файла в конце пути – wave.txt, а суффикс этого файла – .txt.
Экземпляры Path также предлагают функцию with_name, которая позволяет легко создавать новые объекты Path с другими именами:
wave = Path("ocean", "wave.txt")
tides = wave.with_name("tides.txt")
print(wave)
print(tides)
Если мы запустим этот код, мы получим следующий результат:
ocean/wave.txt
ocean/tides.txt
Код сначала создает экземпляр Path, который указывает на файл wave.txt. Затем мы вызываем метод with_name для wave, чтобы вернуть второй экземпляр Path, указывающий на новый файл tides.txt. Часть пути ocean/ (что указывает на каталог) остается неизменной, и в результате остается конечный путь – ocean/tides.txt.
Доступ к порождающим объектам
В некоторых ситуациях бывает необходимо получить доступ к каталогам, содержащим заданный путь. Рассмотрим такой пример:
shark = Path("ocean", "animals", "fish", "shark.
print(shark)
print(shark.parent)
Если мы запустим этот код, мы получим вывод, который выглядит следующим образом:
ocean/animals/fish/shark.txt
ocean/animals/fish
Атрибут parent в экземпляре Path возвращает ближайший порождающий объект данного пути. В этом случае он возвращает каталог, содержащий файл shark.txt: ocean/animals/fish.
Мы можем получить доступ к атрибуту parent несколько раз подряд, чтобы пройти вверх по дереву порождающих объектов данного файла:
shark = Path("ocean", "animals", "fish", "shark.txt")
print(shark)
print(shark.parent.parent)
Запустив этот код, вы получите:
ocean/animals/fish/shark.txt
ocean/animals
Результат похож на предыдущий, но в этот раз мы прошли еще один уровень выше, обратившись к атрибуту .parent дважды. Два каталога выше файла shark.txt – это каталог ocean/animals.
Вывод списка файлов с помощью метода glob
Также класс Path можно использовать для вывода списка файлов с помощью метода glob.
Допустим, у нас есть такая структура каталогов:
└── ocean
├── animals
│ └── fish
│ └── shark.txt
├── tides.txt
└── wave.txt
Каталог ocean содержит файлы tides.txt и wave.txt. У нас есть файл shark.txt, вложенный в каталог ocean, каталог animals и каталог fish: ocean/animals/fish.
Чтобы перечислить все файлы .txt в каталоге ocean, можно использовать такой код:
for txt_path in Path("ocean").glob("*.txt"):
print(txt_path)
Этот код даст следующий результат:
ocean/wave.txt
ocean/tides.txt
Шаблон метода glob “*.txt” находит все файлы, заканчивающиеся на .txt. Поскольку данный пример кода выполняет этот метод в каталоге ocean, он возвращает два файла: wave.txt и tides.txt.
Примечание: Если вы хотите продублировать результаты, показанные в этом примере, в вашей системе, вам необходимо имитировать в ней структуру каталогов, показанную здесь.
Метод glob также можно использовать рекурсивно. Чтобы вывести все файлы .txt в каталоге ocean и во всех его подкаталогах, можно написать такой код:
for txt_path in Path("ocean").glob("**/*.txt"):
print(txt_path)
Если мы запустим его, мы получим следующий результат:
ocean/wave.txt
ocean/tides.txt
ocean/animals/fish/shark.txt
Часть шаблона ** будет рекурсивно отвечать этому каталогу и всем его подкаталогам. Таким образом, мы получаем не только файлы wave.txt и tides.txt, а и файл shark.txt, который был вложен в ocean/animals/fish.
Вычисление относительных путей
Для вычисления путей относительно друг друга можно использовать метод Path.relative_to. Метод relative_to полезен, если, например, вы хотите получить часть длинного пути к файлу.Давайте рассмотрим следующий код:
shark = Path("ocean", "animals", "fish", "shark.txt")
below_ocean = shark.relative_to(Path("ocean"))
below_animals = shark.relative_to(Path("ocean", "animals"))
print(shark)
print(below_ocean)
print(below_animals)
Если вы запустите его, вы получите такой вывод:
ocean/animals/fish/shark. txt
animals/fish/shark.txt
fish/shark.txt
Метод relative_to возвращает новый объект Path относительно данного аргумента. В нашем примере мы вычисляем путь к shark.txt относительно каталога ocean, а затем относительно каталогов ocean и animals.
Если relative_to не может вычислить ответ, потому что получил неправильный путь, он выдает ValueError:
shark = Path("ocean", "animals", "fish", "shark.txt")
shark.relative_to(Path("unrelated", "path"))
К примеру, из нашего кода мы могли бы получить примерно такое сообщение ValueError:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/Python3.8/pathlib.py", line 899, in relative_to
raise ValueError("{!r} does not start with {!r}"
ValueError: 'ocean/animals/fish/shark.txt' does not start with 'unrelated/path'
unrelated/path не является частью ocean/animals/fish/shark.txt, поэтому Python не может вычислить относительный путь.
Заключение
Модуль pathlib – мощный компонент стандартной библиотеки Python, который позволяет нам быстро управлять путями файловой системы в любой операционной системе. В этом мануале вы научились использовать некоторые ключевые утилиты pathlib для доступа к атрибутам файлов, вывода списка файлов с помощью шаблонов glob и просмотра порождающих файлов и каталогов.
Модуль pathlib предоставляет другие классы и утилиты, которые мы не рассматривали в этом руководстве. Теперь, когда вы владеете основами, вы можете обратиться к документации модуля pathlib, чтобы узнать больше об остальных классах и утилитах pathlib.
Tags: pathlib, Python, Python 3Пути к файлам (File Paths)
Go в примерах: Пути к файлам (File Paths)Пакет | package main |
import ( "fmt" "path/filepath" "strings" ) | |
func main() { | |
| p := filepath.Join("dir1", "dir2", "filename") fmt.Println("p:", p) |
Вы должны всегда использовать | fmt.Println(filepath.Join("dir1//", "filename")) fmt.Println(filepath.Join("dir1/../dir1", "filename")) |
| fmt.Println("Dir(p):", filepath.Dir(p)) fmt.Println("Base(p):", filepath.Base(p)) |
Можно проверить является ли путь абсолютным. | fmt.Println(filepath.IsAbs("dir/file")) fmt.Println(filepath.IsAbs("/dir/file")) |
filename := "config.json" | |
Некоторые имена файлов имеют расширения, следующие
за точкой. Мы можем получить расширение из таких
имен с помощью | ext := filepath.Ext(filename) fmt.Println(ext) |
Чтобы найти имя файла с удаленным расширением,
используйте | fmt.Println(strings.TrimSuffix(filename, ext)) |
| rel, err := filepath.Rel("a/b", "a/b/t/file") if err != nil { panic(err) } fmt.Println(rel) |
rel, err = filepath. Rel("a/b", "a/c/t/file") if err != nil { panic(err) } fmt.Println(rel) } |
$ go run file-paths.go p: dir1/dir2/filename dir1/filename dir1/filename Dir(p): dir1/dir2 Base(p): filename false true .json config t/file ../c/t/file |
Следующий пример: Директории (Directories).
Python 3 Быстрый совет: простой способ работы с путями к файлам в Windows, Mac и Linux | Адам Гейтгей
Одной из небольших неприятностей в программировании является то, что Microsoft Windows использует символ обратной косой черты между именами папок, в то время как почти все остальные компьютеры используют прямую косую черту:
Это случайность компьютерной истории начала 1980-х годов. Первая версия MS-DOS использовала косую черту для указания параметров командной строки. Когда Microsoft добавила поддержку папок в MS-DOS 2. 0, косая черта уже использовалась, поэтому вместо нее использовалась обратная косая черта. Тридцать пять лет спустя мы все еще застряли в этой несовместимости.
Если вы хотите, чтобы ваш код на Python работал как в Windows, так и в Mac/Linux, вам необходимо решить эти проблемы, связанные с платформой. К счастью, в Python 3 есть новый модуль под названием pathlib , который делает работу с файлами почти безболезненной.
Давайте кратко рассмотрим различные способы обработки путей к файлам и посмотрим, как pathlib может сделать вашу жизнь лучше!
Допустим, у вас есть папка данных, содержащая файл, который вы хотите открыть в своей программе Python:
Это неправильный способ закодировать его на Python:
Обратите внимание, что я жестко запрограммировал путь, используя косую черту в стиле Unix, так как я на Mac. Это разозлит пользователей Windows.
Технически этот код по-прежнему будет работать в Windows, потому что в Python есть хак, который распознает косую черту любого типа при вызове open() в Windows. Но даже при этом не стоит зависеть от этого. Не все библиотеки Python будут работать, если вы используете неправильную косую черту в неправильной операционной системе, особенно если они взаимодействуют с внешними программами или библиотеками.
И поддержка Python для смешивания типов косой черты — это хак только для Windows, который не работает в обратном порядке. Использование обратной косой черты в коде полностью провалится на Mac:
По всем этим и многим другим причинам написание кода с жестко заданными строками пути заставит других программистов смотреть на вас с большим подозрением. В общем, вы должны стараться избегать этого.
Модуль Python os.path имеет множество инструментов для решения подобных проблем с файловой системой, характерных для операционной системы.
Вы можете использовать os.path.join() для создания строки пути, используя правильную косую черту для текущей операционной системы:
Этот код будет работать как на Windows, так и на Mac. Проблема в том, что им больно пользоваться. Запись os.path.join() и передача каждой части пути в виде отдельной строки многословна и неинтуитивна.
Поскольку большинство функций в модуле os.path одинаково раздражают в использовании, разработчики часто «забывают» использовать их, даже если они знают лучше. Это приводит к большому количеству кроссплатформенных ошибок и недовольных пользователей.
Python 3.4 представил новую стандартную библиотеку для работы с файлами и путями, которая называется pathlib — и это здорово !
Чтобы использовать его, вы просто передаете путь или имя файла в новый объект Path(), используя косую черту, и он обрабатывает все остальное:
Обратите внимание на две вещи:
- Вы должны использовать косую черту с функциями pathlib . Объект Path() преобразует косую черту в правильный тип косой черты для текущей операционной системы. Хороший!
- Если вы хотите добавить путь, вы можете использовать оператор / прямо в коде. Попрощайтесь с вводом os.path.join(a, b) снова и снова.
И если это все, что сделал pathlib , это было бы хорошим дополнением к Python, но оно делает гораздо больше!
Например, мы можем прочитать содержимое текстового файла, не возясь с открытием и закрытием файла:
Совет: предыдущие примеры содержали ошибки, потому что открытый файл никогда не закрывался. Этот синтаксис полностью исключает эту ошибку.На самом деле, pathlib делает большинство стандартных операций с файлами быстрыми и легкими:
Вы даже можете использовать pathlib для явного преобразования пути Unix в путь в формате Windows:
И если вы ДЕЙСТВИТЕЛЬНО хотите использовать обратную косую черту в своем коде безопасно, вы можете объявить свой путь как отформатированный для Windows, и pathlib может преобразовать его для работы в текущей операционной системе:
относительные пути к файлам, анализировать пути к сетевым ресурсам и генерировать URL-адреса file://. Вот пример, который откроет локальный файл в вашем веб-браузере всего двумя строками кода:
Это был всего лишь крошечный пик на pathlib . Это отличная замена множеству различных функций, связанных с файлами, которые раньше были разбросаны по разным модулям Python. Проверьте это !
Спасибо за внимание! Если вы интересуетесь машинным обучением (или просто хотите понять, что это такое), ознакомьтесь с моей статьей «Машинное обучение — это весело!». Серия или подпишитесь на мою рассылку:
Вы также можете подписаться на меня в Твиттере по адресу @ageitgey или найти меня в LinkedIn.
Передовой опыт: работа с путями в Python — часть 1
Проблема: вывод списка папок и дисковНедавно во время работы над проектом коллега спросил, можно ли составить список содержимого дисков в Python. Конечно вы можете. Более того, поскольку это совсем не сложно, я хотел бы взять этот случай, чтобы проиллюстрировать ключевые рекомендации, рекомендуемые для работы с путями на дисках.
Шаг 1: Как ввести правильный путь?Предполагая, что вы хотите точно получить список определенного пути, мы начинаем с выбора пользовательского каталога в системе Windows 10, что в основном является воспроизводимым примером:
path_dir: str = "C:\Users\sselt\Documents \blog_demo"
Переменные, назначенные при выполнении, немедленно вызывают ошибку:
SyntaxError: (ошибка юникода) кодек 'unicodeescape' не может декодировать байты в позиции 2-3: усечено \UXXXXXXXX escape
Интерпретатор не понимает последовательность символов \U, так как это инициирует символы Unicode аналогичной последовательности. Эта проблема возникает из-за того, что в системе Windows в качестве разделителя пути используется обратная косая черта «\», а в Linux используется косая черта «/». К сожалению, поскольку разделитель Windows также является инициатором различных специальных символов или экранирования в Unicode, он явно все путает. Точно так же, как мы не ожидаем в ближайшее время какой-либо согласованности в использовании десятичных разделителей в разных странах, наш единственный выбор — выбрать одно из трех решений.
Решение 1 – отвратительный вариант
Просто избегайте разделителя Windows и пишите путь, используя только разделители Linux:
path_dir: str = "C:/Users/sselt/Documents/blog_demo"02 Затем интерпретатор распознает правильный путь, полагая, что для начала это была система Linux.
Решение 2 – еще более отвратительный вариант
Используйте управляющие последовательности.
path_dir: str = "C:\\Users\sselt\Documents\\blog_demo"Что меня беспокоит, помимо неразборчивости этого, так это то, что escape-последовательности не используются при каждой комбинации символов-разделителей, только перед «U» и «b».
Решение 3 — элегантное
Используйте необработанные строки с префиксом «r», чтобы указать, что специальные символы не должны оцениваться.
path_dir: str = r"C:\Users\sselt\Documents\blog_demo"Шаг 2. Сканирование файлов
Вернемся к нашей задаче — составить список всех элементов в папке. Мы уже знаем путь.
Простая команда os.listdir выводит список всех строк, т. е. только пути к файлам. Здесь и во всех других примерах я использую подсказки типов для дополнительной документации кода. Этот синтаксис стал доступен, начиная с Python 3.5.
импорт ОС от ввода списка импорта path_dir: str = r"C:\Users\sselt\Documents\blog_demo" content_dir: List[str] = os.listdir(path_dir)Файл в порядке, но меня больше интересует статистика файла, для которой у нас есть os.stat.
Шаг 3. Объединение путей
Чтобы передать путь к файлу, мы должны сначала объединить имя файла и путь. Я часто видел следующие конструкции в дикой природе и даже использовал их, когда начинал. Например:
path_file: str = path_dir + "/" + имя файла path_file: str = path_dir + "\\" + имя файла path_file: str = "{}/{}". format(path_dir, имя файла) path_file: str = f"{path_dir}/{filename}"A и B ужасны, потому что они связывают строки знаком «+», что не нужно в Python.
B особенно отвратительно, потому что в Windows нужен двойной разделитель, иначе он будет оцениваться как escape-последовательность для закрывающей кавычки.
C и D несколько лучше, так как они используют форматирование строк, но они все еще не решают проблему системной зависимости. Если я применяю результат под Windows, я получаю функциональный, но несогласованный путь со смесью разделителей.
имя_файла = "некоторый_файл" print("{}/{}".format(path_dir, имя файла)) ...: 'C:\\Users\\sselt\\Documents\\blog_demo/some_file'
Решение, не зависящее от ОС
Решение от Python: os.sep или os.path.sep . Оба возвращают разделитель путей соответствующей системы. Они функционально идентичны, но второй, более явный синтаксис сразу показывает используемый разделитель.
Значит, можно написать:
path_file = "{}{}{}".format(path_dir, os.sep, filename)Результат будет лучше, но за счет сложного кода, если вы объедините несколько сегментов пути.
Таким образом, принято объединять элементы пути посредством связывания строк. Это еще короче и универсальнее:
path_file = os.sep.join([path_dir, filename])Первый полный запуск
Перейдем в каталог:
для имени файла в os.listdir (path_dir):path_file = os.sep.join([path_dir, имя файла]) print(os.stat(path_file))Один из результатов (не показан) — это st_atime, время последнего обращения к нему, st_mtime для последней модификации и st_ctime для времени создания. Кроме того, st_size дает размер файла в байтах. На данный момент все, что я хочу знать, это размер и дату последней модификации, поэтому я решил сохранить простой формат списка.
импорт ОС от ввода списка импорта, кортежа обзор файлов: Список[Кортеж] = [] content_dir: List[str] = os. listdir(path_dir) для имени файла в content_dir: path_file = os.sep.join([path_dir, имя файла]) статистика = os.stat(path_file) filesurvey.append((path_dir, имя файла, stats.st_mtime, stats.st_size))Окончательная функция с рекурсией
Полученный результат сначала кажется удовлетворительным, но возникают две новые проблемы. Listdir не делает различий между файлами и папками, обращается только к уровню папок и не обрабатывает вложенные папки. Следовательно, нам нужна рекурсивная функция, которая различает файлы и папки. os.path.isdir проверяет для нас, есть ли папка ниже пути.
def collect_fileinfos (path_directory: str, filesurvey: List[Tuple]): content_dir: List[str] = os.listdir(path_directory) для имени файла в content_dir: path_file = os.sep.join([path_directory, имя файла]) если os.path.isdir(path_file): collect_fileinfos (путь_файла, обзор файлов) еще: статистика = os.