## удобный обход папок
Функция `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`.
Будьте осторожны, команды удаления стирают файл, а не перемещают его в корзину, вне зависимости от операционной системы! После такого удаления восстановить файл может быть сложно или вовсе невозможно.