背景介绍
随着电脑使用时间增长,重复文件(如备份的照片、文档副本)会悄悄占用大量磁盘空间。手动清理不仅耗时,还容易误删重要文件。本文将介绍如何用Python开发一个重复文件查找与清理工具,通过哈希计算识别内容重复的文件,支持安全删除冗余副本,帮你高效释放磁盘空间。
核心思路分析
要解决重复文件问题,需分解为以下步骤:
1. 递归扫描文件:遍历指定文件夹及其子文件夹,收集所有文件路径。
2. 哈希值计算:对每个文件计算MD5哈希(分块读取避免内存溢出),哈希值相同则内容必然相同。
3. 重复文件分组:用字典(哈希值→文件列表)存储重复文件,键为哈希值,值为文件信息(路径、大小、修改时间)。
4. 用户交互与安全删除:展示重复文件组,让用户选择保留的文件;删除前二次确认,避免误删。
代码实现:分模块讲解
下面是完整的Python实现,包含详细注释:
import os
import hashlib
import time
def scan_directory(directory):
"""递归扫描目录下的所有文件,返回文件路径列表"""
file_paths = []
for root, dirs, files in os.walk(directory):
for file in files:
file_path = os.path.join(root, file)
file_paths.append(file_path)
return file_paths
def get_file_info(file_path):
"""获取文件的路径、大小(字节)、修改时间(格式化字符串)"""
size = os.path.getsize(file_path)
mtime = os.path.getmtime(file_path)
mtime_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(mtime))
return {'path': file_path, 'size': size, 'mtime': mtime_str}
def calculate_file_hash(file_path):
"""分块读取文件,计算MD5哈希(避免大文件内存溢出)"""
hash_md5 = hashlib.md5()
with open(file_path, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b''):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def find_duplicates(file_paths):
"""根据哈希值分组重复文件,返回{哈希值: [文件信息列表]}"""
hash_dict = {}
for file_path in file_paths:
try:
file_hash = calculate_file_hash(file_path)
file_info = get_file_info(file_path)
if file_hash in hash_dict:
hash_dict[file_hash].append(file_info)
else:
hash_dict[file_hash] = [file_info]
except Exception as e:
print(f"警告:处理文件 {file_path} 时出错({e}),已跳过。")
# 只保留重复的组(文件数≥2)
return {k: v for k, v in hash_dict.items() if len(v) > 1}
def display_duplicate_groups(duplicates):
"""格式化输出所有重复文件组"""
if not duplicates:
print("未找到重复文件!")
return
group_idx = 1
for hash_val, file_list in duplicates.items():
print(f"\n--- 重复文件组 {group_idx}(哈希前缀:{hash_val[:8]}...) ---")
for i, file_info in enumerate(file_list):
size_mb = file_info['size'] / (1024 * 1024)
print(f" {i+1}. {file_info['path']}(大小:{size_mb:.2f}MB,修改时间:{file_info['mtime']})")
group_idx += 1
def select_keep_files(duplicates):
"""用户选择每组中保留的文件,返回哈希值→保留文件的映射"""
keep_map = {}
for hash_val, file_list in duplicates.items():
print(f"\n处理重复组(哈希前缀:{hash_val[:8]}...):")
for i, file_info in enumerate(file_list):
size_mb = file_info['size'] / (1024 * 1024)
print(f" {i+1}. {file_info['path']}(大小:{size_mb:.2f}MB,修改时间:{file_info['mtime']})")
choice = input("请输入要保留的文件序号(1~{}),回车保留第一个:".format(len(file_list)))
try:
idx = int(choice) - 1 if choice.strip() else 0
keep_map[hash_val] = file_list[idx] if 0 <= idx < len(file_list) else file_list[0]
except (ValueError, IndexError):
print("输入无效,默认保留第一个文件。")
keep_map[hash_val] = file_list[0]
return keep_map
def delete_duplicate_files(duplicates, keep_map):
"""删除重复文件(保留用户选择的文件),返回删除列表和释放空间"""
deleted = []
freed = 0
confirm = input("\n确认删除?此操作不可撤销!(y/n):").lower()
if confirm != 'y':
return deleted, freed
for hash_val, file_list in duplicates.items():
keep_path = keep_map[hash_val]['path']
for file_info in file_list:
if file_info['path'] != keep_path:
try:
os.remove(file_info['path'])
deleted.append(file_info['path'])
freed += file_info['size']
except Exception as e:
print(f"删除失败:{file_info['path']}({e})")
return deleted, freed
def main():
dirs = input("请输入要扫描的文件夹路径(多个用空格分隔):").split()
all_files = []
for d in dirs:
if os.path.isdir(d):
scanned = scan_directory(d)
all_files.extend(scanned)
print(f"已扫描 {d},找到 {len(scanned)} 个文件")
else:
print(f"警告:{d} 不是有效文件夹,已跳过")
print("\n正在计算哈希...")
duplicates = find_duplicates(all_files)
display_duplicate_groups(duplicates)
if not duplicates:
return
keep_map = select_keep_files(duplicates)
deleted, freed = delete_duplicate_files(duplicates, keep_map)
freed_mb = freed / (1024 * 1024)
print(f"\n--- 结果 ---")
print(f"删除 {len(deleted)} 个文件,释放 {freed_mb:.2f} MB")
for f in deleted:
print(f" - {f}")
if __name__ == "__main__":
main()
关键技术细节解析
- 递归扫描与大文件处理
- 用
os.walk()递归遍历文件夹,自动处理子目录。 - 哈希计算时分块读取文件(每次读4096字节),避免一次性加载大文件导致内存溢出。
- 用
- 哈希值的唯一性与效率
MD5哈希值(128位)的碰撞概率极低,可认为哈希相同则文件内容相同。相比逐字节比较,哈希计算的时间复杂度为O(n)(n为文件大小),但无需存储文件内容,空间效率更高。 -
安全删除的设计
- 用户选择保留的文件后,二次确认防止误删。
- 捕获
os.remove()的异常(如权限不足、文件被占用),避免程序崩溃。
- 用户交互的友好性
- 展示重复文件时,按组清晰列出文件路径、大小、修改时间,方便用户判断保留哪一个。
- 支持“回车默认保留第一个文件”,简化操作流程。
运行与测试
- 准备测试文件:在两个不同文件夹中放入内容相同的文件(如
test.jpg、backup.jpg内容相同)。 - 运行程序:输入文件夹路径(多个路径用空格分隔),工具会自动扫描、计算哈希、展示重复组。
- 交互操作:选择每组保留的文件,确认删除后,工具会输出删除结果和释放的空间。
总结与扩展
通过这个工具,你不仅掌握了文件哈希、递归遍历、字典分组等核心编程技巧,还学会了如何设计“安全操作”流程。在此基础上,你可以扩展功能:
– 增加图形界面(如用 tkinter),提升易用性。
– 支持按文件类型(如图片、视频)过滤扫描。
– 记录删除日志,方便恢复误删文件。
如果你的磁盘正被重复文件拖累,不妨运行这个工具,让它帮你“智能瘦身”吧!