Сравните две версии одной и той же папки и получите имена файлов, которые отличаются - PullRequest
0 голосов
/ 03 мая 2018

Предположим, у меня есть следующая упрощенная структура файлов

main_folder
    |__ foo.json
    |
    |__ sub_folder
          |__bar.json

У меня есть две копии main_folder, например main_folder_v1 и main_folder_v2

Я хочу сравнить обе версии и получить имена всех файлов, которые отличаются (например, получить "foo.json" в случае, если его содержимое было обновлено в main_folder_v2)

И я использую ниже код

import filecmp

comparison_result = filecmp.dircmp(main_folder_v1, main_folder_v2)
files_that_differs = comparison_result.diff_files

Проблема в том, что я получу ["foo.json"] в случае, если он был обновлен в main_folder_v2, но я никогда не получу ["bar.json"], поскольку кажется, что сравнение файлов в sub_folder не выполняется

Есть ли возможность рекурсивного сравнения папок с помощью filecmp и получения имен файлов, которые отличаются или os.walk() является единственным решением?

1 Ответ

0 голосов
/ 03 мая 2018

[Python]: filecmp - Сравнение файлов и каталогов поддерживает рекурсивный обход через dircmp.subdirs. Нет необходимости в os.walk (или любых других подобных функциях).

code.py

import sys
import filecmp
import os


main_folder_v1 = "dir_v1"
main_folder_v2 = "dir_v2"

ROOT_DIR_MARKER = ""


def traverse_dircmp(dircmp_obj, dir_name=ROOT_DIR_MARKER):
    for item in dircmp_obj.diff_files:
        yield os.path.join(dir_name, item)
    for subdir_name in dircmp_obj.subdirs:
        yield from traverse_dircmp(dircmp_obj.subdirs[subdir_name], dir_name=os.path.join(dir_name, subdir_name))
        #for item in traverse_dircmp(dircmp_obj.subdirs[subdir_name], dir_name=os.path.join(dir_name, subdir_name)):
        #    yield item


def traverse_dircmp_list(dircmp_obj, dir_name=ROOT_DIR_MARKER):
    ret = [os.path.join(dir_name, item) for item in dircmp_obj.diff_files]
    for subdir_name in dircmp_obj.subdirs:
        ret.extend(traverse_dircmp_list(dircmp_obj.subdirs[subdir_name], dir_name=os.path.join(dir_name, subdir_name)))
    return ret


def main():
    comparison_object = filecmp.dircmp(main_folder_v1, main_folder_v2)

    comparison_result = traverse_dircmp(comparison_object)
    print("{:s}: {:}".format("Different files (gen)", list(comparison_result)))

    comparison_result_list = traverse_dircmp_list(comparison_object)
    print("{:s}: {:}".format("Different files (list)", comparison_result_list))


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

Вывод (для структуры dir, аналогичной вашей):

(py35x64_test) e:\Work\Dev\StackOverflow\q050157870>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32

Different files (gen): ['foo.json', 'subdir00\\bar.json', 'subdir00\\subdir001\\x.json']
Different files (list): ['foo.json', 'subdir00\\bar.json', 'subdir00\\subdir001\\x.json']

@ EDIT0 :

  • Модифицирована функция traverse_dircmp для возврата списка файлов вместо их печати, как это было запрошено в одном из комментариев

@ EDIT1

  • Добавлены функциональные возможности генератора (в качестве личного упражнения), который является новым (и предпочтительным) стилем и не потребляет память в случае больших директорий ( !! требуется Python3.3 или Выше !! , или yield from оператор может быть заменен на 2 прокомментированные (for и yield) строки под ним)
...