[python]查找文件夹重复文件脚本

功能特点
递归扫描所有子文件夹
找出内容相同的文件(即使文件名不同)
特别找出文件名相同但内容不同的文件
使用MD5哈希值确保准确性
处理文件访问异常,避免程序因权限问题而中断
清晰输出两种类型的重复文件信息

输出说明
脚本会输出两种类型的重复文件:
内容重复的文件:这些文件的内容完全相同(MD5哈希相同),无论文件名是否相同
同名但内容不同的文件:这些文件有相同的文件名但内容不同(MD5哈希不同)

注意事项
对于非常大的文件,计算哈希值可能需要一些时间
程序会跳过无法访问的文件(如权限不足的文件)
结果中只显示有重复的文件组,单独的文件不会显示
这个脚本特别适合您提到的场景,即有些文件名相同但大小/内容不同的文件也需要被识别出来。

import os
import hashlib
from collections import defaultdict

def get_file_hash(file_path, chunk_size=8192):
    """计算文件的MD5哈希值"""
    hash_md5 = hashlib.md5()
    try:
        with open(file_path, "rb") as f:
            for chunk in iter(lambda: f.read(chunk_size), b""):
                hash_md5.update(chunk)
        return hash_md5.hexdigest()
    except (IOError, OSError):
        return None

def find_duplicate_files(start_path):
    """查找重复文件"""
    # 存储文件哈希值和路径的映射
    hash_map = defaultdict(list)
    
    # 存储文件名和路径的映射(用于找出同名但内容不同的文件)
    name_map = defaultdict(list)
    
    # 遍历所有文件
    for root, dirs, files in os.walk(start_path):
        for filename in files:
            file_path = os.path.join(root, filename)
            try:
                # 记录文件名
                name_map[filename].append(file_path)
                
                # 计算文件哈希
                file_hash = get_file_hash(file_path)
                if file_hash:
                    hash_map[file_hash].append(file_path)
            except (OSError, IOError):
                continue
    
    # 找出内容重复的文件
    content_duplicates = {hash_val: paths for hash_val, paths in hash_map.items() if len(paths) > 1}
    
    # 找出同名但可能内容不同的文件
    name_duplicates = {name: paths for name, paths in name_map.items() if len(paths) > 1}
    
    # 找出同名且内容不同的文件
    same_name_diff_content = {}
    for name, paths in name_duplicates.items():
        # 获取这些文件的哈希值
        hashes = {}
        for path in paths:
            file_hash = get_file_hash(path)
            if file_hash:
                if file_hash not in hashes:
                    hashes[file_hash] = []
                hashes[file_hash].append(path)
        
        # 如果有多个不同的哈希值,说明同名但内容不同
        if len(hashes) > 1:
            same_name_diff_content[name] = hashes
    
    return content_duplicates, same_name_diff_content

def main():
    current_dir = os.getcwd()
    print(f"正在扫描目录: {current_dir}")
    
    content_duplicates, same_name_diff_content = find_duplicate_files(current_dir)
    
    if not content_duplicates and not same_name_diff_content:
        print("没有找到重复文件。")
        return
    
    # 输出内容重复的文件
    if content_duplicates:
        print("\n找到以下内容重复的文件:")
        for i, (file_hash, files) in enumerate(content_duplicates.items(), 1):
            print(f"\n组 {i} (哈希: {file_hash}):")
            for file_path in files:
                print(f"  - {file_path}")
        print(f"\n总共找到了 {len(content_duplicates)} 组内容重复的文件。")
    
    # 输出同名但内容不同的文件
    if same_name_diff_content:
        print("\n找到以下同名但内容不同的文件:")
        for i, (filename, hash_groups) in enumerate(same_name_diff_content.items(), 1):
            print(f"\n文件名: {filename}")
            for j, (file_hash, files) in enumerate(hash_groups.items(), 1):
                print(f"  变体 {j} (哈希: {file_hash}):")
                for file_path in files:
                    print(f"    - {file_path}")
        print(f"\n总共找到了 {len(same_name_diff_content)} 个同名但内容不同的文件。")

if __name__ == "__main__":
    main()