Глобальная замена в деревьях каталогов (Visitor)

globalnaya zamena v derevyah katalogov visitor Законченные системные программы

Но раз уж я затронул этот вопрос, то, имея общий класс для обхода дерева, легко написать и подкласс для глобального поиска и замены. В примере 6.20 приводится определение класса ReplaceVisitor, наследующего класс FileVisitor, который переопределяет метод visitfile так, чтобы глобально заменять все вхождения одной строки другой строкой во всех текстовых файлах, находящихся в корневом каталоге и ниже. Он также составляет список всех изменившихся файлов, чтобы их можно было просмотреть и проверить автоматически сделанные изменения (можно, например, автоматически вызывать текстовый редактор для каждого измененного файла).

Пример 6.20. PP4E\Tools\visitor_replace.py

Использование: “python \Tools\visitor_replace.py rootdir fromStr toStr”.

Выполняет глобальный поиск с заменой во всех файлах в дереве каталогов: заменяет fromStr на toStr во всех текстовых файлах; это мощный, но опасный инструмент!! visitor_edit.py запускает редактор, чтобы дать возможность проверить и внести коррективы, и поэтому он более безопасный; чтобы просто получить список соответствующих файлов, используйте visitor_collect.py; режим простого вывода списка здесь напоминает SearchVisitor и CollectVisitor;

import sys

from visitor import SearchVisitor

class ReplaceVisitor(SearchVisitor):

Заменяет fromStr на toStr в файлах в каталоге startDir и ниже; имена изменившихся файлов сохраняются в списке obj.changed

def __init__(self, fromStr, toStr, listOnly=False, trace=0): self.changed = [] self.toStr = toStr self.listOnly = listOnly

SearchVisitor.__init__(self, fromStr, trace)

def visitmatch(self, fname, text): self.changed.append(fname) if not self.listOnly:

fromStr, toStr = self.context, self.toStr text = text.replace(fromStr, toStr) open(fname, ‘w’).write(text)

if __name__ == ‘__main__’:

listonly = input(‘List only?’) == ‘y’

visitor = ReplaceVisitor(sys.argv[2], sys.argv[3], listonly) if listonly or input(‘Proceed with changes?’) == ‘y’:

visitor.run(startDir=sys.argv[1])

action = ‘Changed’ if not listonly else ‘Found’ print(‘Visited %d files’ % visitor.fcount) print(action, ‘%d files:’ % len(visitor.changed)) for fname in visitor.changed: print(fname)

Чтобы применить этот сценарий к определенному дереву каталогов, выполните команду, как показано ниже, указав соответствующую искомую строку и строку замены. На моем, жутко нерасторопном нетбуке, обработка дерева с 1429 файлами, из которых 101 потребовалось изменить, заняла примерно три секунды реального времени, когда система была не слишком занята другими задачами:

C:\\PP4E\Tools> visitor_replace.py C:\temp\PP3E\Examples PP3E PP4E

List only?y

Visited 1429 files

Found 101 files:

C:\temp\PP3E\Examples\README-root.txt

C:\temp\PP3E\Examples\PP3E\echoEnvironment.pyw C:\temp\PP3E\Examples\PP3E\Launcher.py

…большое количество имен файлов, соответствующих критерию поиска, опущено…

C:\\PP4E\Tools> visitor_replace.py C:\temp\PP3E\Examples PP3E PP4E

List only?n

Proceed with changes?y

Visited 1429 files

Changed 101 files:

C:\temp\PP3E\Examples\README-root.txt

C:\temp\PP3E\Examples\PP3E\echoEnvironment.pyw C:\temp\PP3E\Examples\PP3E\Launcher.py

…большое количество имен изменившихся файлов опущено…

C:\\PP4E\Tools> visitor_replace.py C:\temp\PP3E\Examples PP3E PP4E

List only?n

Proceed with changes?y

Visited 1429 files

Changed 0 files:

Естественно, проверить работу этого сценария можно с помощью сценария visitor (и суперкласса SearchVisitor):

C:\\PP4E\Tools> visitor.py 2 C:\temp\PP3E\Examples PP3E

Found in 0 files, visited 1429

C:\\PP4E\Tools> visitor.py 2 C:\temp\PP3E\Examples PP4E

C:\temp\PP3E\Examples\README-root.txt has PP4E

C:\temp\PP3E\Examples\PP3E\echoEnvironment.pyw has PP4E C:\temp\PP3E\Examples\PP3E\Launcher.py has PP4E

…большое количество имен файлов, соответствующих критерию поиска, опущено…

Found in 101 files, visited 1429

Это одновременно очень мощный и опасный сценарий. Если заменяемая строка может обнаружиться в неожиданных местах, запуск определенного здесь объекта ReplaceVisitor может разрушить все дерево файлов. С другой стороны, если строка является чем-то очень специфическим, этот объект поможет избежать необходимости вручную редактировать подозрительные файлы. Например, адреса веб-сайтов в файлах HTML достаточно специфичны, чтобы случайно появиться в других местах.

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

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