Skip to content

2つのディレクトリ内のファイル差分を比較するツール#

ライブラリのインポート:

import os
import filecmp
from openpyxl import Workbook
必要なライブラリをインポートしています。osモジュールはファイルパスの操作、filecmpモジュールはディレクトリやファイルの比較、openpyxlモジュールはExcelファイルの操作に使用されます。

比較結果の格納用リスト:

results = []
比較結果を格納するための空のリストを作成します。

ファイル比較を行う再帰関数:

def compare_recursive(folder1, folder2):
    dcmp = filecmp.dircmp(folder1, folder2)
    ...
指定された2つのフォルダを比較するための再帰関数です。dcmpには2つのフォルダの比較結果が格納されます。

ディレクトリ1にだけ存在するファイルを処理:

for only_in_dir1 in dcmp.left_only:
    file_path = os.path.relpath(os.path.join(folder1, only_in_dir1), dir1_path)
    results.append((file_path, "", "削除"))
dcmp.left_onlyにはディレクトリ1にだけ存在するファイルが含まれていますそれらのファイルに対して相対パスを計算してリストに追加しています

ディレクトリ2にだけ存在するファイルを処理:

for only_in_dir2 in dcmp.right_only:
    file_path = os.path.relpath(os.path.join(folder2, only_in_dir2), dir2_path)
    results.append(("", file_path, "新規"))
同様に、dcmp.right_onlyにはディレクトリ2にだけ存在するファイルが含まれており、相対パスを計算してリストに追加しています。

差分のファイルを処理:

for diff_file in dcmp.diff_files:
    file1_path = os.path.join(folder1, diff_file)
    file2_path = os.path.join(folder2, diff_file)
    rel_file1_path = os.path.relpath(file1_path, dir1_path)
    rel_file2_path = os.path.relpath(file2_path, dir2_path)
    results.append((rel_file1_path, rel_file2_path, "差分あり"))
dcmp.diff_filesには差分のあるファイルが含まれていますそれぞれのファイルについて相対パスを計算してリストに追加しています

ディレクトリ1とディレクトリ2の両方に存在し、内容が同じファイルを処理:

for common_file in dcmp.common_files:
    file1_path = os.path.join(folder1, common_file)
    file2_path = os.path.join(folder2, common_file)
    rel_file1_path = os.path.relpath(file1_path, dir1_path)
    rel_file2_path = os.path.relpath(file2_path, dir2_path)
    results.append((rel_file1_path, rel_file2_path, "差分なし"))
dcmp.common_filesには両方のディレクトリに存在するが内容が同じファイルが含まれていますそれぞれのファイルについて相対パスを計算してリストに追加しています

サブディレクトリを再帰的に比較:

for subfolder in dcmp.common_dirs:
    compare_recursive(os.path.join(folder1, subfolder), os.path.join(folder2, subfolder))
dcmp.common_dirsには共通のサブディレクトリが含まれていますそれぞれのサブディレクトリに対して再帰的に同じ比較処理を行っています

結果をExcelに書き込む:

wb = Workbook()
ws = wb.active
ws.append(["ディレクトリ1", "ディレクトリ2", "状態"])

for result in results:
    ws.append(result)

wb.save(excel_path)

結果をExcelファイルに書き込んでいます。A列にディレクトリ1からの相対パス、B列にディレクトリ2からの相対パス、C列にファイルの状態が記録されます。

比較するディレクトリのパスとExcelファイルのパスを指定して処理を実行:

dir1_path = "./dir1/"
dir2_path = "./dir2/"
excel_path = "comparison_results.xlsx"
compare_and_write_results(dir1_path, dir2_path, excel_path)

実際にスクリプトを実行する部分です。比較するディレクトリのパスとExcelファイルのパスを指定して関数を呼び出しています。

compare_and_write_excel.py
import os
import filecmp
from openpyxl import Workbook

def compare_and_write_results(dir1_path, dir2_path, excel_path):
    # 結果を格納するリスト
    results = []

    # ファイル比較を行う再帰関数
    def compare_recursive(folder1, folder2):
        dcmp = filecmp.dircmp(folder1, folder2)

        # ディレクトリ1にだけ存在するファイルを取得
        for only_in_dir1 in dcmp.left_only:
            file_path = os.path.relpath(os.path.join(folder1, only_in_dir1), dir1_path)
            results.append((file_path, "", "削除"))

        # ディレクトリ2にだけ存在するファイルを取得
        for only_in_dir2 in dcmp.right_only:
            file_path = os.path.relpath(os.path.join(folder2, only_in_dir2), dir2_path)
            results.append(("", file_path, "新規"))

        # 差分のファイルを取得
        for diff_file in dcmp.diff_files:
            file1_path = os.path.join(folder1, diff_file)
            file2_path = os.path.join(folder2, diff_file)
            rel_file1_path = os.path.relpath(file1_path, dir1_path)
            rel_file2_path = os.path.relpath(file2_path, dir2_path)
            results.append((rel_file1_path, rel_file2_path, "差分あり"))

        # ディレクトリ1とディレクトリ2に両方存在するが内容が同じファイルを取得
        for common_file in dcmp.common_files:
            file1_path = os.path.join(folder1, common_file)
            file2_path = os.path.join(folder2, common_file)
            rel_file1_path = os.path.relpath(file1_path, dir1_path)
            rel_file2_path = os.path.relpath(file2_path, dir2_path)
            results.append((rel_file1_path, rel_file2_path, "差分なし"))

        # サブディレクトリを再帰的に比較
        for subfolder in dcmp.common_dirs:
            compare_recursive(os.path.join(folder1, subfolder), os.path.join(folder2, subfolder))

    # フォルダの再帰的な比較を開始
    compare_recursive(dir1_path, dir2_path)

    # 結果をExcelに書き込む
    wb = Workbook()
    ws = wb.active
    ws.append(["ディレクトリ1", "ディレクトリ2", "状態"])

    for result in results:
        ws.append(result)

    wb.save(excel_path)

    print("比較結果をExcelに書き込みました:", excel_path)

# 比較するディレクトリのパス
dir1_path = "./dir1/"
dir2_path = "./dir2/"

# Excelファイルのパス
excel_path = "comparison_results.xlsx"

# 関数を呼び出して処理を実行
compare_and_write_results(dir1_path, dir2_path, excel_path)

compare_recursive関数に特定のファイル名の場合は比較を無視する処理を追加

def compare_recursive(folder1, folder2):
    dcmp = filecmp.dircmp(folder1, folder2)

    # スキップするファイル名を指定
    skip_files = ["skip_file.txt"]

    # ディレクトリ1にだけ存在するファイルを取得
    for only_in_dir1 in dcmp.left_only:
        file_path = os.path.relpath(os.path.join(folder1, only_in_dir1), dir1_path)
        if only_in_dir1 not in skip_files:
            results.append((file_path, "", "削除"))

    # ディレクトリ2にだけ存在するファイルを取得
    for only_in_dir2 in dcmp.right_only:
        file_path = os.path.relpath(os.path.join(folder2, only_in_dir2), dir2_path)
        if only_in_dir2 not in skip_files:
            results.append(("", file_path, "新規"))

    # 差分のファイルを取得
    for diff_file in dcmp.diff_files:
        file1_path = os.path.join(folder1, diff_file)
        file2_path = os.path.join(folder2, diff_file)
        rel_file1_path = os.path.relpath(file1_path, dir1_path)
        rel_file2_path = os.path.relpath(file2_path, dir2_path)
        if diff_file not in skip_files:
            results.append((rel_file1_path, rel_file2_path, "差分あり"))

    # ディレクトリ1とディレクトリ2に両方存在するが内容が同じファイルを取得
    for common_file in dcmp.common_files:
        file1_path = os.path.join(folder1, common_file)
        file2_path = os.path.join(folder2, common_file)
        rel_file1_path = os.path.relpath(file1_path, dir1_path)
        rel_file2_path = os.path.relpath(file2_path, dir2_path)
        if common_file not in skip_files:
            results.append((rel_file1_path, rel_file2_path, "差分なし"))

    # サブディレクトリを再帰的に比較
    for subfolder in dcmp.common_dirs:
        compare_recursive(os.path.join(folder1, subfolder), os.path.join(folder2, subfolder))