用Python 3编写的文件和目录查重工具
实现思路:
文件查重:
使用文件的MD5哈希值来判断文件内容是否相同。
遍历目录中的所有文件,计算每个文件的MD5哈希值,并将哈希值存储到字典中。
如果发现相同的哈希值,说明文件内容重复。
文件夹查重:
使用文件夹的名称和内容来判断是否重复。
遍历目录中的所有文件夹,记录文件夹的名称和内容(文件列表),并检查是否有重复。
代码实现:
import os
import hashlib
from collections import defaultdict
def calculate_file_hash(file_path, hash_algo=hashlib.md5, chunk_size=8192):
"""
计算文件的哈希值(基于文件内容)。
参数:
- file_path: str,文件的完整路径。
- hash_algo: 哈希算法,默认为 MD5,可选 SHA256 等。
- chunk_size: int,每次读取的文件块大小,默认 8192 字节(8KB)。
返回:
- 文件的哈希值(十六进制字符串)。
"""
hasher = hash_algo() # 初始化哈希对象
try:
with open(file_path, 'rb') as f: # 以二进制方式读取文件
while chunk := f.read(chunk_size): # 按块读取文件内容
hasher.update(chunk) # 更新哈希值
return hasher.hexdigest() # 返回计算出的哈希值
except (IOError, OSError):
print(f"无法读取文件: {file_path},跳过...")
return None # 读取失败返回 None
def find_duplicate_files(directory):
"""
查找重复的文件(跨目录对比,忽略文件名,仅比较内容)。
参数:
- directory: str,要检查的根目录。
返回:
- duplicate_files: dict,包含重复文件的哈希值和对应文件路径列表。
"""
file_hash_map = defaultdict(list) # 存储哈希值到文件路径的映射
for root, _, files in os.walk(directory): # 遍历目录
for file_name in files:
file_path = os.path.join(root, file_name) # 获取完整文件路径
file_hash = calculate_file_hash(file_path) # 计算文件哈希值
if file_hash:
file_hash_map[file_hash].append(file_path) # 存入字典
# 过滤出重复的文件(哈希值相同且文件数大于 1)
duplicate_files = {hash_val: paths for hash_val, paths in file_hash_map.items() if len(paths) > 1}
return duplicate_files
def find_duplicate_directories(directory):
"""
查找重复的文件夹(跨目录对比)。
参数:
- directory: str,要检查的根目录。
返回:
- duplicate_dirs: dict,包含重复目录内容的哈希值和对应路径列表。
"""
dir_content_map = defaultdict(list) # 存储文件夹内容哈希值到路径的映射
for root, dirs, _ in os.walk(directory): # 遍历目录
for dir_name in dirs:
dir_path = os.path.join(root, dir_name) # 获取完整目录路径
try:
# 获取文件夹内容(文件和子文件夹)
dir_contents = []
for dir_root, dir_dirs, dir_files in os.walk(dir_path):
# 记录子文件夹路径
dir_contents.extend(os.path.join(dir_root, name) for name in dir_dirs)
# 记录文件路径
dir_contents.extend(os.path.join(dir_root, name) for name in dir_files)
# 排序目录内容,确保顺序一致(避免路径遍历顺序导致不同哈希值)
dir_contents = tuple(sorted(dir_contents))
dir_content_map[dir_contents].append(dir_path) # 存入字典
except (IOError, OSError):
print(f"无法读取目录: {dir_path},跳过...")
# 过滤出重复的文件夹(内容相同且路径数大于 1)
duplicate_dirs = {contents: paths for contents, paths in dir_content_map.items() if len(paths) > 1}
return duplicate_dirs
def print_duplicates(duplicates, title):
"""
打印重复的文件或文件夹信息。
参数:
- duplicates: dict,包含重复项的哈希值或内容元组及其路径列表。
- title: str,描述打印内容("文件" 或 "文件夹")。
"""
if not duplicates:
print(f"没有找到重复的{title}。")
return
print(f"\n找到的重复{title}:")
for key, paths in duplicates.items():
print(f"以下{title}是重复的:")
for path in paths:
print(f" - {path}")
print()
def main():
"""
主函数:获取用户输入路径,查找重复文件和文件夹,并输出结果。
"""
directory = input("请输入要检查的目录路径: ").strip()
if not os.path.isdir(directory): # 检查目录是否有效
print("指定的目录不存在!")
return
# 查找重复文件
print("\n正在查找重复的文件...")
duplicate_files = find_duplicate_files(directory)
print_duplicates(duplicate_files, "文件")
# 查找重复文件夹
print("\n正在查找重复的文件夹...")
duplicate_dirs = find_duplicate_directories(directory)
print_duplicates(duplicate_dirs, "文件夹")
if __name__ == "__main__":
main()
使用说明:
将代码保存为
find_duplicates.py
。在终端或命令行中运行脚本:
输入要检查的目录路径。
脚本会输出重复的文件和文件夹。
示例输出:
假设目录结构如下:
运行脚本后,输出可能为:
正在查找重复的文件...
找到的重复文件:
以下文件是重复的:
- /test_dir/dir1/file1.txt
- /test_dir/dir2/file3.txt
- /test_dir/dir3/file5.txt
以下文件是重复的:
- /test_dir/dir1/file2.txt
- /test_dir/dir2/file4.txt
正在查找重复的文件夹...
没有找到重复的文件夹。
注意事项:
性能:对于大文件或大量文件,计算哈希值可能会比较耗时。
文件夹查重:文件夹查重基于文件夹的名称和内容,如果文件夹内容相同但名称不同,则不会被判定为重复。
评论