Вот готовый профессиональный скрипт. Для оптимизации производительности я применил важный прием: скрипт сначала группирует файлы по размеру, и только те файлы, которые имеют одинаковый размер, отправляются на расчет SHA-256 хеша. Это в десятки раз ускоряет работу, так как не нужно читать содержимое каждого уникального файла. Сохраните этот код в файл dedup.py и запустите: python3 dedup.py `python import os import hashlib import sys def get_file_hash(filepath, block_size=65536): """Вычисляет SHA-256 хеш файла по частям, чтобы не забивать оперативную память.""" sha256 = hashlib.sha256() try: with open(filepath, 'rb') as f: for block in iter(lambda: f.read(block_size), b''): sha256.update(block) return sha256.hexdigest() except (PermissionError, OSError): return None def format_size(size): """Преобразует байты в читаемый формат.""" for unit in ['B', 'KB', 'MB', 'GB', 'TB']: if size < 1024: return f"{size:.2f} {unit}" size /= 1024 def print_progress(current, total): """Рисует простой прогресс-бар в консоли.""" width = 40 percent = float(current) * 100 / total filled = int(width * current // total) bar = '█' * filled + '-' * (width - filled) sys.stdout.write(f'\rProgress: |{bar}| {percent:.1f}% ({current}/{total})') sys.stdout.flush() def main(): current_dir = os.getcwd() print(f"Scanning directory: {current_dir}\n") # 1. Сбор всех файлов больше 1 КБ и их группировка по размеру # (Файлы с разным размером заведомо не могут быть дубликатами) size_map = {} all_files_count = 0 print("Phase 1: Scanning filesystem...") for root, _, files in os.walk(current_dir): for name in files: path = os.path.join(root, name) try: size = os.path.getsize(path) if size < 1024: # Игнорируем файлы меньше 1 КБ continue all_files_count += 1 size_map.setdefault(size, []).append(path) except (PermissionError, OSError): continue # Оставляем только те группы, где больше одного файла с таким размером potential_duplicates = [paths for size, paths in size_map.items() if len(paths) > 1] files_to_hash = [path for group in potential_duplicates for path in group] total_to_hash = len(files_to_hash) # 2. Поиск дубликатов по SHA-256 среди файлов с одинаковым размером hash_map = {} processed_count = 0 if total_to_hash > 0: print(f"Phase 2: Analyzing {total_to_hash} potential duplicates...") for path in files_to_hash: file_hash = get_file_hash(path) if file_hash: hash_map.setdefault(file_hash, []).append(path) processed_count += 1 print_progress(processed_count, total_to_hash) print() # Перенос строки после прогресс-бара else: print("No potential duplicates found based on file size.") # 3. Формирование отчета duplicates = {h: paths for h, paths in hash_map.items() if len(paths) > 1} total_waste_space = 0 total_dup_files = 0 print("\n" + "="*60) print("DUPLICATE FILES REPORT") print("="*60) if not duplicates: print("No duplicate files found.") else: for h, paths in duplicates.items(): file_size = os.path.getsize(paths[0]) # Сколько места можно освободить (размер * (кол-во файлов - 1)) waste = file_size * (len(paths) - 1) total_waste_space += waste total_dup_files += (len(paths) - 1) print(f"\nGroup: {h[:16]}... (Size: {format_size(file_size)})") print(f"Potential saving: {format_size(waste)}") for p in paths: print(f" - {p}")