Функция walk() модуля OS в Python
Сегодня говорим о таком важном инструменте для работы с файловой системой, как функция walk(), которая позволяет получать сведения о данных (файлах и каталогах) и вносить в них изменения.
Назначение функции os.walk()
Модуль OS в Python часто используется для взаимодействия с функциями операционной системы, в частности — для управления файлами и каталогами. Чтобы выполнить навигацию по файловой системе, нужно применить одну из функций модуля — os.walk().

Фрагмент кода ниже находит все папки и файлы в указанной директории и выводит их полный путь на экран. Вот как он работает:
- функция
os.walk()проходит по всем файлам и папкам в указанной директории и предоставляет три значения: (1) текущая папка, (2) список подпапок и (3) список файлов; - затем используется
os.path.join()для получения полного пути к файлу или папке.
После этого путь выводится на экран:
import os
def main():
directory = "highload_today_directory"
for root, dirs, files in os.walk(directory):
print("Исходный каталог:", root)
print("Вложенные папки:")
for dir_name in dirs:
print(os.path.join(root, dir_name))
print("Файлы:")
for file_name in files:
print(os.path.join(root, file_name))
print()
if __name__ == "__main__":
main()
Аргументы функции os.walk()
В подавляющем большинстве случаев для функции os.walk() достаточно использовать аргумент top — путь к директории, с которой нужно выполнять обход файловой системы.
Синтаксис функции предусматривает также три необязательных аргумента:
- Так, если передать функции
os.walk()аргументtopdownс логическим значениемFalse, перебор выполняется от вложенных каталогов к внешним. Соответственно, если этот параметр принимает значениеTrue(по умолчанию), обход идет от верхнего уровня к внутренним директориям. - Другой необязательный аргумент —
onerror, функция-обработчик ошибок (по умолчаниюNone). - И последний необязательный аргумент —
followlinks(по умолчаниюFalse). Это логическое значение, указывающее, нужно ли следовать символическим ссылкам. При значенииfollowlinks=Falseсимволические ссылки игнорируются, а обход ограничен только текущей структурой директорий.
Преимущества os.walk()
За счет особенностей своей работы функция os.walk() может сэкономить вам ресурсы. В процессе обращения к os.walk(), выполняется обход файловой системы с указанного стартового пути. Во время обхода, os.walk() генерирует кортежи с информацией о текущем каталоге, вложенных каталогах, а также файлах.
При этом функция os.walk() не возвращает все значения сразу, а вместо этого возвращает особый тип объекта — объект-генератор. Он генерирует значения по мере надобности, запоминая текущее состояние.
То есть, если у вас есть цикл for, вы можете остановить обход директорий, если в этом есть необходимость, а затем продолжить с этого момента.
Например, это может выглядеть так:
import os start_path = '/какой-то/длинный/путь/к/директории' generator = os.walk(start_path) # Проходимся по первым 206 файлам for root, dirs, files in generator: for file in files: # Обработка файла print(os.path.join(root, file)) # Выключаем обход после 206 файлов if len(files) > 206: break else: continue break # Снова запускаем обход с этапа, на котором остановились for root, dirs, files in generator: for file in files: # Обработка файла print(os.path.join(root, file))
Когда мы используем объект-генератор в цикле for, он автоматически получает новые значения из os.walk() на каждой итерации. Это означает, что информация о директориях и файлах генерируется по мере обхода файловой системы, а не загружается сразу.
В случаях, когда идет обработка большого массива данных, скажем, миллиона файлов, такой подход экономит приличный объем памяти, требуемый для хранения этих значений.
Обратите внимание на синтаксис в адресе пути — для разных ОС он будет свой. Путь, указанный на Linux и macOS будет содержать прямой слеш (/), в то время как путь на Windows будет выглядеть так:
start_path = 'C:\\Users\\Username\\Documents'
Либо с префиксом на указание сырой (raw) строки для которой обратный слеш не экранируется:
start_path = r'C:\Users\Username\Documents'
Примеры использования функции os.walk()
Нахождение дубликатов
Стандартная библиотека Python содержит модуль hashlib, который можно задействовать в паре с функцией os.walk() для поиска в директориях файлов-дубликатов. В этом случае программа будет сравнивать их хеш-суммы и делать вывод об идентичности данных:
import os
import hashlib
def get_file_hash(file_path):
"""Определяет хеш файла"""
with open(file_path, 'rb') as f:
data = f.read()
file_hash = hashlib.sha256(data).hexdigest()
return file_hash
def find_duplicate_files(start_path):
"""Выявляет идентичные файлы в указанном каталоге, а также во всех вложенных каталогах"""
file_hashes = {} # Словарь для записи хешей файлов
duplicate_files = [] # Список для хранения дубликатов файлов
for root, dirs, files in os.walk(start_path):
for file_name in files:
file_path = os.path.join(root, file_name)
file_hash = get_file_hash(file_path)
if file_hash in file_hashes:
duplicate_files.append((file_path, file_hashes[file_hash]))
else:
file_hashes[file_hash] = file_path
return duplicate_files
start_path = '/path/to/directory'
duplicates = find_duplicate_files(start_path)
if duplicates:
print("Обнаружены дубликаты:")
for file1, file2 in duplicates:
print(file1, "и", file2)
else:
print("Файлов с идентичным содержанием не обнаружено")
В коде выше идет обращение к функции get_file_hash(), чтобы вычислить хеш каждого файла по алгоритму SHA-256. После этого хеш и путь к файлу сохраняются в словарь file_hashes. Если будет найден файл с аналогичным хешем, он добавится в список duplicate_files.
Пакетное переименование
Предположим, необходимо переименовать группу файлов в директории C:\foto, добавив к каждому префикс Highloadtoday_. В этом случае мы можем использовать код:
import os start_dir = start_path = 'C:\\foto' add_prefix = 'Highloadtoday_' for root, dirs, files in os.walk(start_dir): for file in files: file_path = os.path.join(root, file) edit_file_name = add_prefix + file edit_file_path = os.path.join(root, edit_file_name) os.rename(file_path, edit_file_path) print(file_path, edit_file_name)
Обратите внимание! Переменная edit_file_name в коде остается неизменной на протяжении выполнения скрипта.
Даже если в файловом менеджере вручную вернуть имя файла к исходному состоянию, переменная edit_file_name остается с префиксом Highloadtoday_.
Поэтому в консоли Python будет ошибочно писать в названии файла Highloadtoday_Highloadtoday_Highloadtoday_....., добавляя префикс в начало имени при каждом следующем запуске скрипта (даже если мы переименовали файл).
Чтобы устранить этот мелкий баг, просто используйте другую функцию модуля — os.path.basename(). Она позволит считать имя файла без пути и добавить префикс корректно:
import os start_dir = 'C:\\foto' add_prefix = 'Highloadtoday_' for root, dirs, files in os.walk(start_dir): for file in files: if not file.startswith(add_prefix): file_path = os.path.join(root, file) file_name = os.path.basename(file_path) # Получаем имя файла без пути edit_file_name = add_prefix + file_name # Добавляем префикс к имени файла edit_file_path = os.path.join(root, edit_file_name) os.rename(file_path, edit_file_path) print(file_path, edit_file_name)
Заключение
Теперь вы знаете, как в Python легко и просто обходить директории, получая информацию о каталогах и файлах вашей файловой системы. Функция os.walk() эффективна при работе с большим объемом данных, а также легко комбинируется с прочими стандартными командами Python для выполнения сложных операций над файловой системой.
Подробнее про работу с модулем OS вы можете узнать из этого видео:

Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: