Функция os.walk для рекурсивного обхода файловой системы

Раздел: Администрирование -> Системные вызовы

Основной метод обхода: os.walk

Функция os.walk является стандартным инструментом для рекурсивного обхода дерева каталогов в Python. Она возвращает генератор, который на каждом шаге выдает кортеж из трёх элементов: текущий путь, список подкаталогов, список файлов. Это наиболее эффективное и читаемое решение для большинства задач администрирования.

import os

for root, dirs, files in os.walk('/path/to/start'):
print('Текущая директория:', root)
print('Подкаталоги:', dirs)
print('Файлы:', files)

Python os environ (переменные окружения os.environ в python)

Типичная ошибка:

При обходе больших деревьев может возникать ошибка PermissionError (отсутствие прав доступа к некоторым папкам). По умолчанию os.walk не обрабатывает такие исключения, и выполнение прерывается. Решение – передать аргумент onerror с функцией-обработчиком.

def error_handler(exception):
print('Ошибка доступа:', exception)
return None # Продолжить обход

for root, dirs, files in os.walk('/', onerror=error_handler):
# обработка

Python os getenv (получение переменной окружения os.getenv в python)

Как обойти только файлы определённого расширения?

С помощью фильтрации внутри цикла:

for root, dirs, files in os.walk('.'):
for file in files:
if file.endswith('.py'):
print(os.path.join(root, file))

Python os listdir (список файлов в директории os.listdir в python)

Проблема:

При большом количестве файлов фильтрация в цикле может быть неоптимальной. Альтернатива – изменять список dirs на лету для исключения ненужных подкаталогов.

Как ограничить глубину обхода?

Параметром topdown и модификацией списка dirs:

max_depth = 2
start_depth = 0

for root, dirs, files in os.walk('.'):
depth = root.replace('.', '').count(os.sep)
if depth >= max_depth:
dirs.clear() # не заходить глубже

Python os exists (проверка существования пути os.path.exists в python)

Ошибка:

Если путь содержит точки, подсчёт глубины может быть неточным. Лучше использовать os.path.relpath или вести счётчик.

Как получить полные пути файлов без конкатенации?

Использовать os.path.join с генератором:

full_paths = (os.path.join(root, file) for root, _, files in os.walk('.') for file in files)

Python os walk (обход директорий os.walk в python)

Как игнорировать скрытые файлы и каталоги (начинающиеся с точки)?

for root, dirs, files in os.walk('.'):
dirs[:] = [d for d in dirs if not d.startswith('.')]
files = [f for f in files if not f.startswith('.')]

Python имя компьютера (имя компьютера в python)

Предостережение:

Изменение списка dirs влияет на последующий обход. Если удалить элемент, os.walk не зайдёт в этот подкаталог.

Как обработать символические ссылки?

По умолчанию os.walk не следит за ссылками. Чтобы включить следование, используйте аргумент followlinks=True:

for root, dirs, files in os.walk('.', followlinks=True):
# обработка

Python выполнение команды (выполнение команд в python)

Осторожно:

Если ссылки ведут в родительские каталоги, может возникнуть бесконечный цикл. Рекомендуется отслеживать посещённые inode.

Как получить размеры всех файлов в дереве?

total_size = 0
for root, _, files in os.walk('.'):
for file in files:
file_path = os.path.join(root, file)
try:
total_size += os.path.getsize(file_path)
except FileNotFoundError:
pass

Расширенные примеры использования os.walk

Пример 1: Построение дерева каталогов с отступами

Пример
import os

def show_tree(path, indent=0):
for root, dirs, files in os.walk(path):
level = root.replace(path, '').count(os.sep)
indent = ' ' * 4 * level
print(f'{indent}{os.path.basename(root)}/')
subindent = ' ' * 4 * (level + 1)
for file in files:
print(f'{subindent}{file}')

show_tree('.')
Результат (пример):
my_project/
README.md
src/
main.py
utils.py
tests/
test_main.py

Пример 2: Поиск дубликатов файлов по содержимому (хеш)

Пример
import os
import hashlib

def hash_file(filepath):
h = hashlib.sha256()
with open(filepath, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b''):
h.update(chunk)
return h.hexdigest()

hashes = {}
for root, _, files in os.walk('.'):
for file in files:
path = os.path.join(root, file)
h = hash_file(path)
hashes.setdefault(h, []).append(path)

duplicates = {k: v for k, v in hashes.items() if len(v) > 1}
print('Найдены дубликаты:', duplicates)
Вывод:
Найдены дубликаты: {'a1b2c3...': ['dir1/file.txt', 'dir2/file.txt']}

Пример 3: Асинхронный обход с concurrent.futures

Пример
import os
from concurrent.futures import ThreadPoolExecutor

def process_file(filepath):
# какая-то операция, например, чтение метаданных
return os.path.getsize(filepath)

file_list = []
for root, _, files in os.walk('.'):
for file in files:
file_list.append(os.path.join(root, file))

with ThreadPoolExecutor() as executor:
results = list(executor.map(process_file, file_list))
print('Размеры файлов:', results[:10])

Проблема:

При большом количестве файлов ThreadPoolExecutor может создать излишнее количество потоков. Рекомендуется ограничивать max_workers.

Пример 4: Использование pathlib как альтернативы (rglob)

Пример
from pathlib import Path

base_path = Path('.')
for file in base_path.rglob('*.py'):
print(file.resolve())
Результат:
.../script1.py
.../subdir/script2.py

Примечание: Path.rglob реализует рекурсивный обход, но не даёт такого прямого контроля над подкаталогами, как os.walk.

Обход директорий os.walk в Python - comments

En
Python os walk (python)