Функция обхода дерева os. walk

funkciya obhoda dereva os walk Инструменты для работы с файлами и каталогами

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

По своей сути функция os.walk является функцией-генератором — для каждого каталога в дереве она возвращает кортеж из трех элементов, содержащий имя текущего каталога, а также списки всех файлов и всех подкаталогов в текущем каталоге. Так как это функция-генератор, обход дерева обычно реализуется с помощью цикла for (или другого инструмента итераций). В каждой итерации функция перемещается к следующему подкаталогу, а инструкция цикла выполняет свое тело для следующего уровня в дереве (например, открывает все файлы в этом подкаталоге и производит поиск по их содержимому).

На первый взгляд, такое описание может показаться ужасно сложным, но когда вы привыкнете к функции os.walk, все окажется довольно простым. В следующем фрагменте, например, тело цикла выполняется для каждого каталога в дереве с корнем в текущем рабочем каталоге. Цикл просто выводит имя каталога и имена всех файлов в нем, добавляя к ним имя каталога. Описать это на языке Python проще, чем на обычном языке (перед тем как запускать этот пример, я удалил каталог PP3E, чтобы сократить вывод):

>>> import os

>>> for (dirname, subshere, fileshere) in os.walk(‘.’):

print(‘[‘ + dirname + ‘]’)

for fname in fileshere:

print(os.path.join(dirname, fname)) # обработка одного файла

[.]

.\random.bin

.\spam.txt

.\temp.bin

.\temp.txt

[.\parts]

.\parts\part0001

.\parts\part0002

.\parts\part0003

.\parts\part0004

Иными словами, мы реализовали наш собственный, легко изменяемый инструмент рекурсивного вывода содержимого каталога на языке Python, Поскольку нам может потребоваться подправить его и использовать где-нибудь еще, давайте сделаем его постоянно доступным в виде файла модуля, как показано в примере 4.4, — теперь, когда мы проработали детали в интерактивном режиме.

Пример 4.4. PP4E\System\Filetools\lister_walk.py

“выводит список файлов в дереве каталогов с помощью os.walk

import sys, os

def lister(root): # для корневого каталога

for (thisdir, subshere, fileshere) in os.walk(root): # перечисляет

print(‘[‘ + thisdir + ‘]’) # каталоги в дереве

for fname in fileshere: # вывод файлов в каталоге

path = os.path.join(thisdir, fname) # добавить имя каталога print(path)

if __name__ == ‘__main__’: lister(sys.argv[1]) # имя каталога в

# командной строке

При таком оформлении данный программный код можно также выполнять из командной строки. Ниже приводится пример запуска его для получения списка содержимого другого корневого каталога, который передается в аргументе командной строки:

C:\\PP4E\System\Filetools> python lister_walk.py C:\temp\test [C:\temp\test]

C:\temp\test\random.bin

C:\temp\test\spam.txt

C:\temp\test\temp.bin

C:\temp\test\temp.txt

[C:\temp\test\parts]

C:\temp\test\parts\part0001

C:\temp\test\parts\part0002

C:\temp\test\parts\part0003

C:\temp\test\parts\part0004

Ниже приводится более сложный пример использования функции os.walk. Предположим, что имеется дерево каталогов с файлами, и вам необходимо отыскать в нем все файлы с программным кодом на языке Python, которые ссылаются на модуль mimetypes (с этим модулем мы познакомимся в главе 6). Ниже демонстрируется один из способов (хотя и слишком специфичный и не универсальный) решения поставленной задачи:

>  >> import os

>  >> matches = []

>  >> for (dirname, dirshere, fileshere) in os.walk(r’C:\temp\PP3E\Examples’):

for filename in fileshere:

if filename.endswith(‘.py’):

pathname = os.path.join(dirname, filename)

if ‘mimetypes’ in open(pathname).read():

matches.append(pathname)

>  >> for name in matches: print(name)

C:\temp\PP3E\Examples\PP3E\Internet\Email\mailtools\mailParser.py C:\temp\PP3E\Examples\PP3E\Internet\Email\mailtools\mailSender.py C:\temp\PP3E\Examples\PP3E\Internet\Ftp\mirror\downloadflat.py C:\temp\PP3E\Examples\PP3E\Internet\Ftp\mirror\downloadflat_modular.py C:\temp\PP3E\Examples\PP3E\Internet\Ftp\mirror\ftptools.py

C:\temp\PP3E\Examples\PP3E\Internet\Ftp\mirror\uploadflat.py C:\temp\PP3E\Examples\PP3E\System\Media\playfile.py

Данная реализация в цикле обходит все файлы в каждом из подкаталогов, отыскивает файлы с расширением .py, содержащие искомую строку. Если совпадение найдено, полное имя файла добавляется в объект списка с результатами. Как вариант, мы могли бы просто создать список всех файлов с расширением .py и организовать поиск требуемой строки в цикле for уже после обхода дерева. Так как в главе 6 мы представим более универсальное решение для этого типа задач, то оставим пока все, как есть.

Если вам будет интересно узнать, что в действительности происходит внутри генератора os.walk, попробуйте несколько раз вызвать его метод __next__ (или передать его встроенной функции next), как это автоматически делается циклом for, — каждый раз вы будете перемещаться к очередному подкаталогу в дереве:

>  >> gen = os.walk(r’C:\temp\test’)

>  >> gen.__next__()

(‘C:\\temp\\test’, [‘parts’], [‘random.bin’, ‘spam.txt’, ‘temp.bin’, ‘temp. txt’])

>  >> gen.__next__()

(‘C:\\temp\\test\\parts’, [], [‘part0001’, ‘part0002’, ‘part0003’, ‘part0004’]) >>> gen.__next__()

Traceback (most recent call last):

File “<stdin>”, line 1, in <module>

StopIteration

Описание функции os.walk в руководстве по библиотеке содержит более подробную информацию. Например, эта функция поддерживает порядок обхода не только в направлении сверху вниз, но и снизу вверх — достаточно передать функции необязательный аргумент topdown=False, и вызывающий программный код получит возможность сократить количество посещаемых ветвей дерева, удаляя имена из списка подкаталогов в возвращаемых кортежах.

Для создания списков имен на каждом уровне в дереве каталогов функция os.walk использует функцию os.listdir, с которой мы встречались выше, возвращающую имена файлов и каталогов без определенного порядка и без путей к каталогам. Прежде чем вернуть очередной результат, функция os.walk делит этот список на списки каталогов и файлов (точнее, некаталогов). Обратите также внимание, что функция os.walk использует тот же список подкаталогов, который она возвращает вызывающему программному коду, чтобы затем спуститься в подкаталоги. Списки являются изменяемыми объектами, которые можно изменять непосредственно, поэтому, изменяя содержимое полученного списка подкаталогов, вызывающий программный код может оказывать влияние на дальнейшую работу os.walk. Например, удаляя имена каталогов, можно сократить число посещаемых ветвей, а отсортировав список, можно определить очередность обхода подкаталогов.

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Каталог сайтов Всего.ру
Оцените статью
Секреты программирования
Добавить комментарий