Обход каталогов и поиск файлов
os.walk(), шаблоны glob и фильтрация файлов по типу или дате.
«Обход каталогов и поиск файлов» — бесплатный урок AI Agents на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Agents, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Agents содержит 4 уроков всего.
Зачем агентам нужен обход каталогов
Агентам часто требуется находить файлы, соответствующие определённым критериям: все файлы Python в кодовой базе, все CSV-файлы в каталоге данных или все недавние журналы. Python предоставляет три основных инструмента: os.walk(), Path.iterdir() и Path.rglob(). Каждый из них имеет свои преимущества в зависимости от глубины поиска.
import os
from pathlib import Path
# Count all files in a directory tree
root = Path('/tmp/agent_workspace')
file_count = sum(1 for f in root.rglob('*') if f.is_file())
print(f'Found {file_count} files under {root}')os.walk() — рекурсивный обход каталогов
os.walk(root) возвращает кортеж (dirpath, dirnames, filenames) для каждого каталога в дереве. Это классический подход Python к рекурсивному обходу, который даёт детальный контроль над тем, в какие вложенные каталоги переходить.
import os
import tempfile
# --- demo setup: build a small project tree so the walk has something to show ---
root = tempfile.mkdtemp(prefix='project_')
os.makedirs(os.path.join(root, 'src'), exist_ok=True)
os.makedirs(os.path.join(root, '.git'), exist_ok=True)
with open(os.path.join(root, 'README.md'), 'w') as f:
f.write('demo')
with open(os.path.join(root, 'src', 'main.py'), 'w') as f:
f.write('print(1)')
for dirpath, dirnames, filenames in os.walk(root):
# Skip hidden directories (like .git)
dirnames[:] = [d for d in dirnames if not d.startswith('.')]
print(f'In directory: {dirpath}')
print(f' Subdirs: {dirnames}')
print(f' Files: {filenames}')
for filename in filenames:
full_path = os.path.join(dirpath, filename)
print(f' File: {full_path}')
Path.iterdir() — список одного уровня
Path.iterdir() перечисляет непосредственное содержимое каталога — он не выполняет рекурсивный обход вложенных каталогов. Используйте его, когда нужны только непосредственные элементы каталога и требуется избежать перехода на более глубокие уровни.
from pathlib import Path
data_dir = Path('data')
data_dir.mkdir(exist_ok=True)
(data_dir / 'a.csv').write_text('x')
(data_dir / 'sub').mkdir(exist_ok=True)
for item in data_dir.iterdir():
if item.is_file():
print(f'FILE: {item.name} ({item.stat().st_size} bytes)')
elif item.is_dir():
print(f'DIR: {item.name}/')
csv_files = [f for f in data_dir.iterdir()
if f.is_file() and f.suffix == '.csv']
print(f'Found {len(csv_files)} CSV files')Path.rglob() — рекурсивный поиск по шаблону
Path.rglob(pattern) рекурсивно находит все файлы, соответствующие шаблону glob. Это самый лаконичный способ найти все файлы определённого типа в любом месте дерева каталогов. Обозначение ** в glob означает «любое количество каталогов».
from pathlib import Path
project = Path('/tmp/my_project')
# Find all Python files recursively
python_files = list(project.rglob('*.py'))
print(f'Found {len(python_files)} Python files:')
for f in python_files:
print(f' {f.relative_to(project)}')
# Find all JSON files
json_files = list(project.rglob('*.json'))
# Find files matching a name pattern
test_files = list(project.rglob('test_*.py'))
print(f'Found {len(test_files)} test files')glob.glob() — сопоставление с шаблоном
glob.glob(pattern, recursive=True) — традиционный интерфейс glob. При значении recursive=True подстановочный символ ** соответствует любому пути вложенного каталога. Эта функция возвращает строки, тогда как pathlib.rglob возвращает объекты Path.
import glob
# Find all CSV files recursively
csv_files = glob.glob('data/**/*.csv', recursive=True)
print(f'Found {len(csv_files)} CSV files')
for f in csv_files:
print(f' {f}')
# Find all log files in a specific directory (non-recursive)
logs = glob.glob('/var/log/*.log')
# Find files matching multiple criteria
import fnmatch
all_files = glob.glob('/tmp/**/*', recursive=True)
config_files = [
f for f in all_files
if fnmatch.fnmatch(f, '*.yaml') or fnmatch.fnmatch(f, '*.yml')
]
print(f'Found {len(config_files)} YAML config files')Фильтрация по расширению файла
При обходе каталогов фильтруйте файлы по расширению с помощью Path.suffix (оно включает точку, например '.py') или проверяйте расширение на принадлежность к набору разрешённых расширений. Для фильтрации по нескольким расширениям это быстрее и точнее, чем шаблоны glob.
from pathlib import Path
directory = Path('/tmp/mixed_files')
ALLOWED_EXTENSIONS = {'.py', '.js', '.ts', '.json', '.yaml'}
# Filter by allowed extensions
code_files = [
f for f in directory.rglob('*')
if f.is_file() and f.suffix.lower() in ALLOWED_EXTENSIONS
]
print(f'Found {len(code_files)} code/config files')
# Group files by extension
from collections import defaultdict
by_ext = defaultdict(list)
for f in directory.rglob('*'):
if f.is_file():
by_ext[f.suffix].append(f)
for ext, files in sorted(by_ext.items()):
print(f'{ext}: {len(files)} files')Фильтрация по размеру файла
Иногда агентам требуется находить файлы, размер которых выше или ниже заданного порога: пропускать крошечные пустые файлы или не обрабатывать огромные файлы, способные переполнить память. Используйте Path.stat().st_size, чтобы получить размер файла в байтах.
from pathlib import Path
data_dir = Path('/tmp/data')
MIN_SIZE = 1024 # 1 KB — skip empty/tiny files
MAX_SIZE = 50_000_000 # 50 MB — skip very large files
processable = []
skipped_small = []
skipped_large = []
for f in data_dir.rglob('*.json'):
if not f.is_file():
continue
size = f.stat().st_size
if size < MIN_SIZE:
skipped_small.append(f.name)
elif size > MAX_SIZE:
skipped_large.append(f.name)
else:
processable.append(f)
print(f'Processable: {len(processable)}')
print(f'Too small: {len(skipped_small)}')
print(f'Too large: {len(skipped_large)}')Фильтрация по времени изменения
Агентам в конвейерах с инкрементальной обработкой нужно обрабатывать только файлы, изменившиеся после последнего запуска. Используйте stat().st_mtime (время изменения в виде метки времени Unix), чтобы находить недавно изменённые файлы.
from pathlib import Path
import time
import datetime
data_dir = Path('/tmp/data')
# Files modified in the last 24 hours
cutoff = time.time() - (24 * 60 * 60)
recent_files = [
f for f in data_dir.rglob('*.log')
if f.is_file() and f.stat().st_mtime > cutoff
]
print(f'Modified in last 24h: {len(recent_files)} files')
# Sort by modification time (newest first)
recent_files.sort(key=lambda f: f.stat().st_mtime, reverse=True)
for f in recent_files[:5]: # top 5 most recent
mtime = datetime.datetime.fromtimestamp(f.stat().st_mtime)
print(f' {f.name}: {mtime.strftime("%Y-%m-%d %H:%M:%S")}')Пропуск скрытых файлов и системных каталогов
При обходе репозиториев кода или пользовательских каталогов пропускайте скрытые файлы (начинающиеся с .) и системные каталоги, такие как .git, __pycache__, node_modules и .venv. В них содержатся тысячи файлов, не имеющих отношения к большинству агентов.
from pathlib import Path
SKIP_DIRS = {'.git', '__pycache__', 'node_modules', '.venv',
'.env', 'dist', 'build', '.mypy_cache'}
def iter_source_files(root, extensions):
root = Path(root)
for path in root.rglob('*'):
# Skip if any parent is in SKIP_DIRS
if any(part in SKIP_DIRS for part in path.parts):
continue
# Skip hidden files
if path.name.startswith('.'):
continue
if path.is_file() and path.suffix in extensions:
yield path
python_files = list(iter_source_files('/tmp/project', {'.py'}))
print(f'Found {len(python_files)} Python source files')Создание инвентаризации файлов
Инвентаризация файлов — это структурированное описание дерева каталогов, полезное агентам, которым необходимо спланировать работу до начала обработки. Соберите имя, путь, размер, расширение и время изменения в список словарей, который можно сериализовать в JSON.
from pathlib import Path
import datetime
import json
def build_inventory(root_dir, pattern='**/*'):
root = Path(root_dir)
inventory = []
for f in root.glob(pattern):
if not f.is_file():
continue
stat = f.stat()
inventory.append({
'name': f.name,
'path': str(f.relative_to(root)),
'extension': f.suffix,
'size_bytes': stat.st_size,
'modified': datetime.datetime.fromtimestamp(
stat.st_mtime
).isoformat()
})
return sorted(inventory, key=lambda x: x['path'])
inventory = build_inventory('/tmp/data')
with open('file_inventory.json', 'w') as out:
json.dump(inventory, out, indent=2)
print(f'Inventoried {len(inventory)} files')Отслеживание изменений в каталоге
Некоторым агентам нужно реагировать на появление новых файлов в каталоге. Хотя для промышленной эксплуатации лучше всего подходит полноценная библиотека для наблюдения за файлами, например watchdog, простой подход заключается в периодическом сканировании каталога и сравнении результатов с известным набором файлов.
from pathlib import Path
import time
def watch_for_new_files(watch_dir, extension='.json', interval=5):
watch_dir = Path(watch_dir)
known_files = set(watch_dir.glob(f'*{extension}'))
print(f'Watching {watch_dir} for new {extension} files...')
while True:
time.sleep(interval)
current_files = set(watch_dir.glob(f'*{extension}'))
new_files = current_files - known_files
for f in new_files:
print(f'New file detected: {f.name}')
process_new_file(f) # handle the new file
known_files = current_files
def process_new_file(file_path):
print(f'Processing: {file_path}')
# --- demo (one polling cycle, without the infinite while True loop) ---
import tempfile
demo_dir = Path(tempfile.mkdtemp())
known_files = set(demo_dir.glob('*.json'))
print(f'Watching {demo_dir} for new .json files...')
(demo_dir / 'result_a.json').write_text('{}', encoding='utf-8')
(demo_dir / 'result_b.json').write_text('{}', encoding='utf-8')
current_files = set(demo_dir.glob('*.json'))
new_files = current_files - known_files
for f in sorted(new_files, key=lambda p: p.name):
print(f'New file detected: {f.name}')
process_new_file(f)
Быстрая проверка: rglob и iterdir
Проверьте, насколько хорошо Вы поняли методы обхода каталогов.
Повторение обхода каталогов
Теперь Вы можете найти любой файл, необходимый Вашему агенту:
- os.walk() — полный контроль над рекурсивным обходом; изменяйте
dirnamesнепосредственно, чтобы исключать вложенные каталоги - Path.iterdir() — список непосредственных элементов одного уровня
- Path.rglob('*.ext') — самый удобный рекурсивный поиск по шаблону
- glob.glob('**/*.ext', recursive=True) — традиционная альтернатива, возвращающая строки
- Фильтруйте по
.suffixдля расширения, по.stat().st_sizeдля размера и по.stat().st_mtimeдля времени изменения - Всегда пропускайте скрытые файлы и системные каталоги, такие как
.gitиnode_modules
Часто задаваемые вопросы
Урок «Обход каталогов и поиск файлов» бесплатный?
Да — полный текст урока «Обход каталогов и поиск файлов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Agents, подпишись на CoddyKit PRO. Курс AI Agents содержит 4 уроков всего.
Чему я научусь в уроке «Обход каталогов и поиск файлов»?
os.walk(), шаблоны glob и фильтрация файлов по типу или дате. Ты практикуешь AI Agents с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать AI Agents?
Предыдущий опыт не требуется. AI Agents на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Обход каталогов и поиск файлов»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке AI Agents?
Да. Каждый урок AI Agents включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Чтение и запись файлов в контексте агента
- Обход каталогов и поиск файлов
- Работа с форматами файлов: CSV, JSON и TXT
- Безопасные операции с файлами и обработка ошибок