## удобный обход папок Функция `walk` модуля `os` позволяет обходить все папки, начиная с заданной, и получать на каждой итерации списки всех файлов и папок на этом уровне. См. документацию: [`os.walk`](https://docs.python.org/3/library/os.html#os.walk) ```python >>> start_path = '.' >>> for root, dirs, files in os.walk(start_path): ... print('Где мы сейчас:', root) ... print('Папки на этом уровне:', dirs) ... print('Файлы на этом уровне:', files) ``` Начальная директория может обозначаться абсолютным путём (например, r'C:\user\docs') или относительным ('./images/'). Подробнее про абсолютные и относительные пути, например, [здесь](http://www.uamedwed.com/blog/web/absolyutnyj-i-otnositelnyj-put-k-fajlam.html). Обратите внимание, что одна точка обозначает текущую директорию: ```python >>> start_path = "." >>> print("Что здесь есть:", os.listdir(start_path)) ``` Две точки обозначают родительский каталог: ```python >>> print("На уровень выше:", os.listdir("..")) >>> print("А в подпапке docs", os.listdir("../docs/")) ``` Пользуясь `os.walk()`, не забывайте, что на каждой итерации в переменных `dirs` и `files` — обыкновенные списки строк, и элементы этих списков — имена папок/файлов (с расширениями), а не пути к ним. Например, чтобы открыть один из этих файлов, нужно склеить адрес и название файла с помощью [`os.path.join()`](https://docs.python.org/3/library/os.path.html#os.path.join). ## содержание папки Модуль стандартной библиотеки `os` (от «operation system») предоставляет множество полезных функций для произведения системных вызовов. Одна из базовых функций этого модуля — `os.listdir`. ```python >>> import os >>> file_list = os.listdir() # список файлов и папок в директории, где запущена программа >>> file_list = os.listdir('.') # синоним >>> file_list = os.listdir('C:/Users') # список имен файлов и папок в данной папке ``` С точки зрения операционной системы нет разницы между файлом, папкой или другим подобным объектом, типа ссылки. Поэтому `os.listdir()` возвращает список как файлов, так и папок. Обратите внимание, что порядок элементов возвращаемого списка не регламентируется, если вам нужно их отсортировать не забудьте сделать это: ```python >>> import os >>> unsorted_file_list = os.listdir() >>> sortetd_file_list = sorted(unsorted_file_list) ``` --- Модуль `os` содержит подмодуль `os.path`, который позволяет работать с путями файлов и папок. Импортировать этот модуль отдельно не нужно, достаточно выполнить `import os`. ## присоединение одной части пути к другой Работа с путями к файлам и папкам как с простыми строками чревата множеством ошибок и может создать проблемы при переносе программы между различными операционными системами. Правильный путь объединить две части пути — это использование `os.path.join`: ```python >>> import os >>> dirpath = '../books' >>> # Здесь filename - имя файла, а не путь от места запуска программы до него: >>> for filename in os.listdir(dirpath): ... # filepath = dirname + filename - сработает неправильно, так как будет не хватать "/" ... filepath = os.path.join(dirname, filename) # поставит "/" или "\" за нас ... with open(filepath, encoding='utf-8') as fd: ... if 'нагваль' in fd.read(): ... print('Книга ' + filename + ' об индейцах') ``` ## извлечение имени файла из пути Функция `os.path.split` совершает обратное действие — отрезает имя файла или ниже лежащей папки от пути: ```python >>> import os >>> path = './work/project/version8/final.txt' >>> dirpath, filename = os.path.split(path) >>> print(dirpath) ./work/project/version8 >>> print(filename) final.txt >>> project_dir, version_dir = os.path.split(dirpath) >>> print(project_dir) ./work/project >>> print(version_dir) version8 ``` ### извлечение расширения Кроме того, может пригодиться функция `os.path.splitext`, котоая отрезает расширение файла: ```python >>> import os >>> path = './work/project/version12/final.txt' >>> base, ext = os.path.splitext(path) >>> print(base, ext, sep='\n') ./work/project/version12/final .txt ``` ## проверка типа файла Кроме прочего, модуль `os.path` содержит функции для проверки существования файла и для определения его типа: ```python >>> import os >>> path = './kursach/text' >>> if os.path.exists(path): ... print(path, 'существует') ... if os.path.isfile(path): ... print(path, '— это файл') ... elif os.path.isdir(path): ... print(path, '— это папка') ... else: ... print(path, '— это ни файл и ни папка') ... else: ... print(path, 'не существует') ``` # манипуляции с файлами и папками Производите все манипуляции с файлами с осторожностью, придерживайтесь правила «семь раз отмерь — один раз отрежь». Не забывайте программно производить все возможные проверки перед выполнением операций. ## создание файла Нет ничего проще, чем создать пустой файл, достаточно открыть несуществующий файл с флагом `'x'`: ```python >>> with open('empty.txt', 'x'): ... pass ``` Конечно, можно было бы использовать флаг `'w'`, но тогда уже существующий файл был бы стёрт. С флагом `'x'` `open` либо создаст новый файл, либо выбросит ошибку. ## создание папки Для создания новой папки используйте `os.mkdir(name)`. Эта функция выбросит ошибку, если по указанному пути уже существует файл или папка. Если вам нужно создать сразу несколько вложенных папок, то смотрите функцию [`os.makedirs(name, exist_ok=False)`](https://docs.python.org/3/library/os.html#os.makedirs). ## перемещение и переименование Для удобной манипуляции с файлами и папками в стандартной библиотеки Python существует специальный модуль `shutil`. Функция `shutil.move(source, destination)` позволяет вам переместить любой файл или папку (даже непустую). Обратите внимание, что если `destination` — это уже существующая папка, то файл/папка будет перемещена внутрь неё, в остальных случаях файл/папка будут скопированы точно по нужному адресу. В случае успеха, функция вернёт новое местоположение файла. Если `destination` существует и не является папкой, то будет выброшена ошибка. ```python >>> import shutil >>> source = 'my_poem.txt' >>> destination = 'trash' >>> # Создаем папку назначения >>> os.mkdir(destination) >>> # Перенесем файл внутрь папки >>> path = shutil.move(source, destination) >>> print(path) trash/my_poem.txt >>> # Перенесем файл обратно >>> new_name = 'poem.txt' >>> final_path = shutil.move(path, new_name) >>> print(final_path) poem.txt ``` Как же переименовать файл? Несмотря на то, что [`os` содержит специальную функцию для переименования](https://docs.python.org/3/library/os.html#os.rename), нужно понимать, что в рамках одной файловой системы перемещение и переименование — это одно и то же. Когда вы переименовываете файл, его содержимое не переписывается на носителе в другое место, просто файловая система теперь обозначает его положение другим путём. ## копирование Скопировать файл можно с помощью функции `shutil.copy(source, destination)`. Правила расположения копии будут те же, что и при использовании `shutil.move`, за тем исключением, что если `destination` существует и не является файлом, то он будет заменён и ошибки это не вызовет. Скопировать папку для операционной системы сложнее, ведь мы всегда хотим скопировать не только папку, но и её содержимое. Для копирования папок используйте `shutil.copytree(source, destination)`. Обратите внимание, что для этой функции `destination` всегда должно быть путём конечного расположения файлов и не может быть уже существующей папкой. ## Удаление Удалить файл можно с помощью функции `os.remove`, а пустую папку с помощью функции `os.rmdir`. А вот для удаления папки с содержимым вновь понадобится `shutil`. Для удаления такой папки используйте `shutil.rmtree`. Будьте осторожны, команды удаления стирают файл, а не перемещают его в корзину, вне зависимости от операционной системы! После такого удаления восстановить файл может быть сложно или вовсе невозможно.