Функция 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.