Поиск расхождений между каталогами

poisk rashozhdenij mezhdu katalogami Законченные системные программы

Прежде чем приступать к программированию, необходимо выяснить, что значит сравнить два дерева каталогов. Если оба дерева имеют одинаковую структуру ветвей и глубину, проблема сводится к сравнению соответствующих файлов в каждом дереве. Однако в общем случае деревья могут иметь произвольную различную форму, глубину и так далее.

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

Иными словами, алгоритм сравнения деревьев должен также попутно выполнять сравнение каталогов. Начнем с реализации сравнения имен файлов для одного каталога, представленной в примере 6.11, так как это вложенная и более простая операция.

Пример 6.11. PP4E\System\Filetools\dirdiff.py

############################################################################## Порядок использования: python dirdiff.py dir1-path dir2-path

Сравнивает два каталога, пытаясь отыскать файлы, присутствующие в одном и отсутствующие в другом.

Эта версия использует функцию os.listdir и выполняет поиск различий между двумя списками. Обратите внимание, что сценарий проверяет только имена файлов, но не их содержимое, — версию, которая сравнивает результаты вызова методов ,read(),sbi найдете в сценарии diffall.py.

##############################################################################

import os, sys

def reportdiffs(unique1, unique2, dir1, dir2):

Генерирует отчет о различиях для одного каталога: часть вывода функции comparedirs

if not (unique1 or unique2):

print(‘Directory lists are identical’)

else:

if unique1:

print(‘Files unique to’, dir1)

for file in unique1:

print(‘,,,’, file)

if unique2:

print(‘Files unique to’, dir2)

for file in unique2: print(‘,,,’, file)

def difference(seq1, seq2):

Возвращает элементы, присутствующие только в seq1;

Операция set(seq1) set(seq2) даст аналогичный результат, но множества являются неупорядоченными коллекциями, поэтому порядок следования элементов в каталоге будет утерян

return [item for item in seq1 if item not in seq2]

def comparedirs(dir1, dir2, files1=None, files2=None):

Сравнивает содержимое каталогов, но не сравнивает содержимое файлов; функции listdir может потребоваться передавать аргумент типа bytes, если могут встречаться имена файлов, недекодируемые на других платформах

print(‘Comparing’, dir1, ‘to’, dir2)

files1 = os.listdir(dir1) if files1 is None else files1

files2 = os.listdir(dir2) if files2 is None else files2

unique1 = difference(files1, files2)

unique2 = difference(files2, files1) reportdiffs(unique1, unique2, dir1, dir2) return not (unique1 or unique2) # true, если нет различий

def getargs():

“Аргументы при работе в режиме командной строки” try:

dir1, dir2 = sys.argv[1:] # 2 аргумента командной строки

except:

print(‘Usage: dirdiff.py dir1 dir2’)

sys.exit(1)

else:

return (dir1, dir2)

if __name__ == ‘__main__’: dir1, dir2 = getargs() comparedirs(dir1, dir2)

Получив списки имен для каждого каталога, этот сценарий просто выбирает уникальные имена в первом каталоге, уникальные имена во втором каталоге и сообщает о найденных уникальных именах как о расхождениях (то есть о файлах, имеющихся в одном каталоге, но отсутствующих в другом). Функция comparedirs возвращает значение True, если расхождения не были обнаружены, что полезно для обнаружения различий при вызове из других программ.

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

C:\\PP4E\System\Filetools> dirdiff.py C:\temp\PP3E\Examples copytemp Comparing C:\temp\PP3E\Examples to copytemp Directory lists are identical

C:\\PP4E\System\Filetools> dirdiff.py C:\temp\PP3E\Examples\PP3E\System ..

Comparing C:\temp\PP3E\Examples\PP3E\System to .. Files unique to C:\temp\PP3E\Examples\PP3E\System App Exits Media moreplus.py

Files unique to ..

more.pyc spam.txt Tester … __init__.pyc

В основе сценария лежит функция difference: она реализует простую операцию сравнения списков. Применительно к каталогам, уникальные элементы представляют различия между деревьями, а общие элементы представляют имена файлов или подкаталогов, которые заслуживают дальнейшего сравнения или обхода. В Python 2.4 и более поздних версиях можно было бы использовать встроенные объекты типа set, если порядок следования имен в результатах не имеет значения — множества не являются последовательностями, поэтому они не сохраняют оригинальный порядок следования элементов в списках, полученных с помощью функции os.listdir. По этой причине (и чтобы не вынуждать пользователей модернизировать сценарий) вместо множеств мы будем использовать функцию, опирающуюся на использование выражения- генератора.

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

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