python对文件夹内文件去重
从爬虫到去重:一个Python脚本解决重复文件困扰
📌 问题起源
昨天写了一个百度图片爬虫,想搜点"斗图"素材。结果爬下来3000多张图片,但一半以上都是重复的!手动删除太费劲,于是写了个Python脚本来去重。本文将分享这个文件去重工具的实现原理、优化思路和使用方法。
🐍 一、文件去重脚本(完整版)
以下脚本基于MD5哈希值比对实现文件去重,支持所有文件类型(图片、文档、视频等)。已在Python 3.6环境下开发测试。
#!/usr/bin/env python # -*- coding:utf-8 -*- # 作者:GuoYabin # 功能:基于MD5的文件夹重复文件删除工具 # 版本:v1.0 # 日期:2017-05-18 import os import hashlib import sys def filecount(): """统计当前目录下的文件数量(仅统计文件,不包含子目录)""" # dir /B 列出所有文件名,find /V /C "" 统计行数 try: count = int(os.popen('dir /B | find /V /C ""').read().strip()) return count except: # 如果不是Windows环境,使用Python原生方式统计 files = [f for f in os.listdir('.') if os.path.isfile(f)] return len(files) def md5sum(filename): """计算文件的MD5哈希值(分块读取,适合大文件)""" # 创建MD5对象 md5 = hashlib.md5() try: with open(filename, 'rb') as f: # 分块读取,避免一次性加载大文件到内存 while True: fb = f.read(8192) # 8KB缓冲区 if not fb: break md5.update(fb) return md5.hexdigest() except Exception as e: print(f"警告: 无法读取文件 {filename} - {str(e)}") return None def delfile(): """删除当前目录下的重复文件(保留第一个出现的版本)""" all_md5 = {} # 存储已保留文件的MD5值 deleted_count = 0 # 遍历当前目录 for root, dirs, files in os.walk(os.getcwd()): for file in files: filepath = os.path.join(root, file) # 计算文件MD5 file_md5 = md5sum(filepath) if file_md5 is None: continue # 如果MD5已存在,则删除文件 if file_md5 in all_md5.values(): try: os.remove(filepath) deleted_count += 1 print(f"删除重复文件: {file}") except Exception as e: print(f"删除失败 {file}: {str(e)}") else: # 记录新文件的MD5 all_md5[file] = file_md5 return deleted_count if __name__ == '__main__': print(''' ========================================== 文件去重工具 v1.0 基于MD5哈希值比对 支持所有文件类型 ========================================== ''') # 确认操作 keyword = input('请确认已把本程序放到要去重的文件夹内,按回车继续,按Ctrl+C退出\n') # 统计去重前文件数 old_count = filecount() print(f'\n去重前共有 {old_count} 个文件\n') print('正在扫描并删除重复文件,请稍候...\n') # 执行去重 deleted = delfile() # 统计去重后文件数 new_count = filecount() # 输出结果 print('\n' + '='*40) print(f'去重完成!') print(f'去重前文件数: {old_count}') print(f'去重后文件数: {new_count}') print(f'共删除重复文件: {deleted} 个') print('='*40) input('\n按回车键退出...')
📦 已编译版本下载(Windows免Python环境)
百度网盘: http://pan.baidu.com/s/1bpalugf 密码:kfk4
⚠️ Python 3.6编译版本需要安装VC2015运行库。如果不想安装运行库,可直接用Python 2.7运行源码。
🔍 二、核心原理与代码解析
2.1 文件去重的基本思路
文件去重的核心是判断两个文件内容是否相同。常用的方法有两种:
| 方法 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 文件大小比较 | 比较文件字节数 | 速度快 | 不同文件可能大小相同(误判) |
| MD5哈希值 | 计算文件内容的哈希指纹 | 准确性高,冲突概率极低 | 大文件计算耗时 |
| 字节逐位比较 | 逐字节对比两个文件 | 100%准确 | 极慢,不适合大量文件 |
本脚本采用MD5哈希值方案,在准确性和性能之间取得平衡。
2.2 关键函数详解
📊 filecount() - 文件计数
# Windows命令方式(速度快) count = int(os.popen('dir /B | find /V /C ""').read()) # 命令解析: # dir /B : 以简洁格式列出当前目录所有文件名 # find /V /C "" : 统计非空行数(/V /C 组合) # 最终得到文件总数
🔑 md5sum() - MD5计算
# 分块读取设计(关键优化) def md5sum(filename): md5 = hashlib.md5() with open(filename, 'rb') as f: while True: fb = f.read(8192) # 每次读取8KB if not fb: break md5.update(fb) return md5.hexdigest() # 为什么要分块? # 如果一次性读取整个文件(f.read()),当处理几百MB的大文件时, # 会占用大量内存,甚至导致内存溢出。分块读取用时间换空间,适合各种大小的文件。
🗑️ delfile() - 去重核心
# 去重算法: 1. 创建一个空字典 all_md5,用于存储已保留文件的MD5 2. 遍历当前目录所有文件 3. 对每个文件计算MD5 4. 如果MD5已存在于字典中,说明是重复文件 → 删除 5. 如果MD5不存在,说明是新文件 → 记录到字典 # 这种算法保证: # - 保留第一个出现的文件 # - 后续所有重复文件都会被删除
⚡ 三、性能优化与改进建议
原脚本在处理大量文件时有几个可以优化的地方:
| 优化点 | 原脚本问题 | 改进方案 |
|---|---|---|
| 大文件处理 | 已采用分块读取,合理 | 可增加缓冲区大小可配置 |
| 先按大小过滤 | 直接计算所有文件的MD5 | 先比较文件大小,只有大小相同的才计算MD5,可减少90%以上的MD5计算 |
| 进度显示 | 静默执行,用户不知道进度 | 添加进度条或定期输出已处理文件数 |
| 子目录支持 | os.walk已支持子目录 | 可增加选项控制是否递归子目录 |
3.1 优化版代码片段(先按大小过滤)
def delfile_optimized(): # 先按文件大小分组 size_dict = {} for root, dirs, files in os.walk(os.getcwd()): for file in files: filepath = os.path.join(root, file) size = os.path.getsize(filepath) if size not in size_dict: size_dict[size] = [] size_dict[size].append(filepath) # 只对大小相同的文件组计算MD5 deleted = 0 for size, file_list in size_dict.items(): if len(file_list) <= 1: continue # 没有重复可能 md5_dict = {} for filepath in file_list: file_md5 = md5sum(filepath) if file_md5 in md5_dict: os.remove(filepath) deleted += 1 else: md5_dict[file_md5] = filepath return deleted
⚠️ 四、使用注意事项
🔴 1. 删除不可恢复
脚本执行永久删除文件,不会放入回收站。建议先在一个测试文件夹中试用,确认效果后再用于重要数据。
🔴 2. 保留策略
脚本默认保留第一个遇到的文件,删除后续重复项。如果需要保留最新文件或特定命名规则的文件,需要对脚本进行修改。
🔴 3. 运行环境
- 源码运行:需要Python 3.6+ 或 Python 2.7
- 编译版本:Windows 7/8/10/2008+,可能需要VC2015运行库
- Linux/macOS:需修改filecount()函数(已提供备选实现)
🔴 4. 文件名编码问题
如果文件名包含特殊字符或非英文字符,在Windows控制台可能出现显示乱码,但不影响文件删除操作。
📊 五、实战测试:3000张图片去重
在包含3128个文件的"斗图"文件夹中测试脚本效果:
| 测试项 | 数值 | 说明 |
|---|---|---|
| 去重前文件数 | 3128 | 爬虫下载的图片 |
| 去重后文件数 | 1456 | 去重率53.4% |
| 执行时间 | 约45秒 | 取决于硬盘速度和文件大小 |
📝 六、总结与扩展
这个脚本虽然简单,但解决了实际问题。从"what a fuck program"到"真香",只差一个去重脚本的距离。未来可以扩展的功能:
- 图形界面:用tkinter或PyQt做个简单的GUI
- 相似图片识别:不只是完全重复,还能识别相似图片(需要用到图像处理库)
- 软链接/硬链接替代删除:节省空间的同时保留文件
- 跨平台支持:完善Linux/macOS的兼容性
—— 如果你也被重复文件困扰,希望这个脚本能帮到你。欢迎收藏转发~
无耻的求一下赞助


浙公网安备 33010602011771号