BmnRoot
Loading...
Searching...
No Matches
rm-dups.py
Go to the documentation of this file.
1import os
2import hashlib
3from datetime import datetime
4
5
6# перевод в timestamp
7def format_date(timestamp):
8 """Преобразует timestamp в читаемую дату."""
9 return datetime.fromtimestamp(timestamp).strftime('%d.%m.%Y %H:%M:%S')
10
11
12# перевод в байты
13def format_size(size_bytes):
14 for unit in ['Б', 'КБ', 'МБ', 'ГБ', 'ТБ']:
15 if size_bytes < 1024:
16 return f"{size_bytes:.2f} {unit}"
17 size_bytes /= 1024
18 return f"{size_bytes:.2f} ПБ"
19
20
21# вычисляет хэш файла
22def get_file_hash(filepath):
23 """Вычисляет SHA-256 хэш файла по частям."""
24 hasher = hashlib.sha256()
25 try:
26 with open(filepath, 'rb') as f:
27 # Читаем по 1МБ, чтобы не забивать ОЗУ
28 while chunk := f.read(1024*1024):
29 hasher.update(chunk)
30 return hasher.hexdigest()
31 except (PermissionError, OSError) as e:
32 print(f"[!] Ошибка доступа к файлу {filepath}: {e}")
33 return None
34
35
37 if not os.path.isdir(directory):
38 print('Указанная директория не найдена')
39 return
40
41 print(f"Сканирование директории: {directory}...")
42
43 # Группировка по размеру (первичный фильтр)
44 files_by_size = {}
45 for root, _, filenames in os.walk(directory):
46 for filename in filenames:
47 path = os.path.join(root, filename)
48 try:
49 # ВАЖНО: проверка размера теперь внутри цикла по filenames
50 size = os.path.getsize(path)
51 files_by_size.setdefault(size, []).append(path)
52 except OSError:
53 continue
54
55 # Хэшируем только те файлы, размер которых совпал
56 files_by_hash = {}
57 for size, paths in files_by_size.items():
58 if len(paths) > 1:
59 for path in paths:
60 f_hash = get_file_hash(path)
61 if f_hash:
62 try:
63 stat = os.stat(path)
64 file_info = {
65 'path': path,
66 'mtime': stat.st_mtime,
67 'size': stat.st_size
68 }
69 files_by_hash.setdefault(f_hash, []).append(file_info)
70 except OSError:
71 continue
72
73 to_delete = []
74
75 print("\n" + "="*80)
76 print("АНАЛИЗ ДУБЛИКАТОВ")
77 print("="*80)
78
79 for f_hash, group in files_by_hash.items():
80 if len(group) > 1:
81 group.sort(key = lambda x: x['mtime'], reverse=True)
82
83 keep_file = group[0]
84 delete_files = group[1:]
85
86 print(f'Оставляем самые свежие файлы : {keep_file["path"]}')
87 print(f" Дата: {format_date(keep_file['mtime'])} | Размер: {format_size(keep_file['size'])}")
88
89 print(f" [БУДУТ УДАЛЕНЫ]:")
90 for duplicates in delete_files:
91 print(f" -- {duplicates['path']}")
92 print(f" Дата: ({format_date(duplicates['mtime'])}) | Размер: ({format_size(duplicates['size'])})")
93 to_delete.append(duplicates['path'])
94 if not to_delete:
95 print("\n[+] Дубликаты не обнаружены. Все дампы уникальны.")
96 return
97
98 print("\n" + "="*80)
99 print(f"ИТОГО: Найдено {len(to_delete)} дубликатов.")
100 confirm = input("Удалить выбранные файлы? (да/нет): ").strip().lower()
101
102 if confirm == 'да':
103 for path in to_delete:
104 try:
105 os.remove(path)
106 print(f"[УДАЛЕНО]: {path}")
107 except Exception as e:
108 print(f"[ОШИБКА]: Не удалось удалить {path}: {e}")
109 print("\n[+] Очистка завершена успешно.")
110 else:
111 print("\n[!] Операция отменена пользователем.")
112
113
114
115if __name__ == "__main__":
116 target_dir = input("Введите путь к папке с дампами: ").strip()
117 clean_database_duplicates(target_dir)
format_size(size_bytes)
Definition rm-dups.py:13
get_file_hash(filepath)
Definition rm-dups.py:22
format_date(timestamp)
Definition rm-dups.py:7
clean_database_duplicates(directory)
Definition rm-dups.py:36