Но раз уж я затронул этот вопрос, то, имея общий класс для обхода дерева, легко написать и подкласс для глобального поиска и замены. В примере 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