Python 業務自動化 | ファイル・フォルダ自動化:基本操作 - 重複ファイル検出

Python Python
スポンサーリンク

重複ファイル検出は「無駄な容量を削減し、フォルダをクリーンに保つ」ための重要な自動化

業務フォルダには、コピー・バックアップ・手動作業の繰り返しによって 同じファイルが複数存在することがよくあります。
重複ファイルが増えると、次のような問題が起きます。

  • ディスク容量を無駄に消費する
  • バックアップ時間が増える
  • どれが最新か分からなくなる
  • 誤って古いファイルを使うリスクが高まる

Python を使うと、ファイル名・サイズ・ハッシュ(内容)を基準に重複を正確に検出できます。
ここでは、初心者でも理解しやすいように、基本から実務テンプレートまで丁寧に解説します。


ファイル名で重複を検出する(最も簡単だが精度は低い)

同じ名前のファイルを探すテンプレート

import os

def find_duplicates_by_name(folder):
    names = {}
    duplicates = []

    for name in os.listdir(folder):
        path = os.path.join(folder, name)
        if os.path.isfile(path):
            if name in names:
                duplicates.append((names[name], path))
            else:
                names[name] = path

    return duplicates

dups = find_duplicates_by_name("data")
for a, b in dups:
    print("重複:", a, "<->", b)
Python

深掘りポイント

  • 「名前が同じ」だけで判断するため、内容が違っても重複扱いになる
  • まずは簡易チェックとして使える
  • 正確な重複検出には次の「サイズ」や「ハッシュ」を使う

ファイルサイズで重複を検出する(精度が上がる)

サイズが同じファイルをグループ化する

import os

def find_duplicates_by_size(folder):
    sizes = {}
    duplicates = []

    for name in os.listdir(folder):
        path = os.path.join(folder, name)
        if os.path.isfile(path):
            size = os.path.getsize(path)
            if size in sizes:
                duplicates.append((sizes[size], path))
            else:
                sizes[size] = path

    return duplicates

dups = find_duplicates_by_size("data")
for a, b in dups:
    print("重複候補:", a, "<->", b)
Python

深掘りポイント

  • サイズが同じ=内容が同じ可能性が高い
  • ただし「サイズは同じだが内容が違う」ケースもある
  • 次の「ハッシュ検証」で完全一致を確認する

ハッシュ(内容)で重複を検出する(最も正確)

SHA-256 で内容を比較するテンプレート

import os
import hashlib

def file_hash(path, chunk_size=1024*1024):
    h = hashlib.sha256()
    with open(path, "rb") as f:
        while chunk := f.read(chunk_size):
            h.update(chunk)
    return h.hexdigest()

def find_duplicates_by_hash(folder):
    hashes = {}
    duplicates = []

    for name in os.listdir(folder):
        path = os.path.join(folder, name)
        if os.path.isfile(path):
            h = file_hash(path)
            if h in hashes:
                duplicates.append((hashes[h], path))
            else:
                hashes[h] = path

    return duplicates

dups = find_duplicates_by_hash("data")
for a, b in dups:
    print("完全一致:", a, "<->", b)
Python

深掘りポイント

  • ハッシュは「内容そのもの」を数値化したもの
  • SHA-256 は衝突(同じハッシュになること)が極めて少ない
  • 最も正確な重複検出方法として実務でよく使われる

例題①:重複ファイルを検出して一覧を CSV に出力する

シナリオ

重複ファイルを一覧化し、後で人間が確認できるようにしたい。

import csv

dups = find_duplicates_by_hash("data")

with open("duplicates.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["File A", "File B"])
    for a, b in dups:
        writer.writerow([a, b])

print("CSV に出力しました")
Python

深掘りポイント

  • 自動削除は危険なので、まずは一覧化して確認する
  • CSV にしておけば Excel で確認しやすい

例題②:重複ファイルを自動削除し、1つだけ残す

シナリオ

完全一致の重複ファイルを削除して容量を節約したい。

import os

dups = find_duplicates_by_hash("data")

for a, b in dups:
    os.remove(b)
    print("削除:", b)
Python

深掘りポイント

  • 必ずハッシュで完全一致を確認してから削除する
  • 名前やサイズだけで削除すると誤削除のリスクが高い
  • 削除前にバックアップを取るのが安全

例題③:サブフォルダも含めて重複ファイルを検出する

os.walk を使って階層全体を探索する

import os
import hashlib

def find_duplicates_recursive(root):
    hashes = {}
    duplicates = []

    for current, dirs, files in os.walk(root):
        for name in files:
            path = os.path.join(current, name)
            h = file_hash(path)
            if h in hashes:
                duplicates.append((hashes[h], path))
            else:
                hashes[h] = path

    return duplicates

dups = find_duplicates_recursive("project")
for a, b in dups:
    print("重複:", a, "<->", b)
Python

深掘りポイント

  • 大規模プロジェクトではサブフォルダに同じファイルが散らばる
  • os.walk で階層全体を探索できる
  • ハッシュ方式なので精度は最高

pathlib を使った読みやすい重複検出

Path オブジェクトで直感的に書ける

from pathlib import Path
import hashlib

def file_hash_path(p: Path):
    h = hashlib.sha256()
    with p.open("rb") as f:
        while chunk := f.read(1024*1024):
            h.update(chunk)
    return h.hexdigest()

def find_duplicates_path(folder: Path):
    hashes = {}
    duplicates = []

    for p in folder.rglob("*"):
        if p.is_file():
            h = file_hash_path(p)
            if h in hashes:
                duplicates.append((hashes[h], p))
            else:
                hashes[h] = p

    return duplicates

dups = find_duplicates_path(Path("data"))
for a, b in dups:
    print("重複:", a, "<->", b)
Python

メリット

  • rglob("*") でサブフォルダも含めて探索
  • Path オブジェクトは読みやすく、保守性が高い

重複ファイル検出を業務で設計するときの視点

  • 名前一致 → 最も簡単だが精度は低い
  • サイズ一致 → 精度が上がるがまだ不十分
  • ハッシュ一致 → 最も正確で実務向け
  • 削除前に一覧化して確認するのが安全
  • サブフォルダを含めるかどうかを明確にする
  • 検出後に ZIP/TAR 圧縮やアーカイブ移動と組み合わせるとさらに便利

タイトルとURLをコピーしました