DupFinder:一个用 Rust 编写的高性能重复文件查找工具
📌 前言
在日常工作和生活中,我们的电脑里经常会积累大量重复文件------下载的重复照片、备份的文档副本、多次保存的视频文件等。这些重复文件不仅占用宝贵的磁盘空间,还让文件管理变得混乱。
今天给大家介绍一个我用 Rust 编写的重复文件查找工具 DupFinder ,它不仅速度快、准确率高,还支持 JSON 导出 和安全删除脚本生成,非常适合需要自动化处理或批量清理重复文件的场景。
项目地址:
🎯 项目背景
为什么要写这个工具?
市面上已经有一些重复文件查找工具,比如:
- fdupes (C 语言):经典工具,但缺少现代化的功能(无 JSON 输出、无彩色界面)
- rdfind (C++):速度快但准确性稍低,且只支持 Linux
我希望开发一个:
- 准确性 100% 的工具(4 层验证)
- 支持 JSON 输出,方便自动化和 CI/CD 集成
- 生成安全的删除脚本,而不是直接删除
- 有友好的彩色界面
- 跨平台支持(Linux、macOS、Windows)
于是 DupFinder 诞生了!
技术选型:为什么选择 Rust?
- ⚡ 性能优异:接近 C/C++ 的性能
- 🔒 内存安全:无 GC,无内存泄漏,无数据竞争
- 📦 易于分发:静态链接,单个二进制文件
- 🛠️ 优秀的工具链:Cargo 包管理,强大的类型系统
✨ 核心功能
1. 四层验证机制(100% 准确)
DupFinder 采用渐进式的 4 层验证策略,确保查找结果 100% 准确:
第 1 层:文件大小比较
↓ (快速排除大小不同的文件)
第 2 层:部分内容哈希 (前 8KB 的 MD5)
↓ (排除开头不同的文件)
第 3 层:完整文件 MD5
↓ (排除内容不同的文件)
第 4 层:逐字节比较
↓ (最终确认 100% 相同)
✅ 确认为重复文件
为什么需要 4 层验证?
- 性能优化:大部分文件在前 1-2 层就被排除,避免不必要的 MD5 计算
- 避免哈希碰撞:虽然 MD5 碰撞概率极低,但逐字节比较确保 100% 准确
- 处理硬链接:检测同一 inode 的文件,避免误报
2. JSON 输出(独家功能)
与 fdupes 和 rdfind 不同,DupFinder 支持导出结构化的 JSON 报告:
bash
dupfinder ~/Downloads --json report.json
JSON 格式示例:
json
{
"scan_info": {
"base_path": "/home/user/Downloads",
"total_groups": 2,
"timestamp": "2025-12-02T16:30:00+08:00"
},
"duplicate_groups": [
{
"group_id": 1,
"file_size": 1048576,
"file_count": 3,
"md5_hash": "5d41402abc4b2a76b9719d911017c592",
"files": [
{
"path": "/home/user/Downloads/file1.txt",
"absolute_path": "/home/user/Downloads/file1.txt"
}
]
}
],
"statistics": {
"total_duplicate_files": 5,
"deletable_files": 3,
"potential_space_savings": 3145728
}
}
应用场景:
- ✅ CI/CD 集成:自动检测代码仓库中的重复文件
- ✅ 自动化脚本:用 Python/Node.js 解析 JSON 进行批处理
- ✅ 数据分析:统计重复文件的分布情况
3. 安全删除脚本生成(独家功能)
DupFinder 不会直接删除文件,而是生成一个可编辑的 Bash 删除脚本:
bash
dupfinder ~/Downloads --delete-script delete.sh
脚本特点:
- ✅ 需要手动输入
yes确认,防止误删 - ✅ 详细的注释,清楚标注保留和删除的文件
- ✅ 可以手动编辑脚本,选择保留哪个文件
- ✅ 完整的错误处理和统计信息
生成的脚本示例:
bash
#!/bin/bash
# 保留: /home/user/Downloads/photo.jpg
# 删除文件 1/2
if [ -f "/home/user/Downloads/photo_copy.jpg" ]; then
echo "删除: /home/user/Downloads/photo_copy.jpg"
rm "/home/user/Downloads/photo_copy.jpg"
fi
4. 其他实用功能
- 🎨 彩色输出:清晰易读的终端界面
- 📊 详细模式:显示 4 层验证的完整过程
- 💾 空间统计:显示可节省的磁盘空间
- 🔗 硬链接检测:智能识别并跳过硬链接(可选)
- 📍 路径显示:支持绝对路径或相对路径
- 🔄 递归扫描:默认扫描所有子目录
📦 安装方法
方式 1:从 crates.io 安装(推荐)
如果你已经安装了 Rust,可以直接使用 Cargo 安装:
bash
cargo install dupfinder
优点:
- 自动编译优化版本
- 自动安装到
~/.cargo/bin - 容易更新:
cargo install dupfinder --force
方式 2:从 GitHub Release 下载
访问 Releases 页面,下载适合你系统的二进制文件:
dupfinder-linux-x86_64- Linux (GNU)dupfinder-linux-x86_64-musl- Linux (静态链接)dupfinder-macos-x86_64- macOS (Intel)dupfinder-macos-aarch64- macOS (Apple Silicon)dupfinder-windows-x86_64.exe- Windows
Linux/macOS 安装:
bash
# 下载后赋予执行权限
chmod +x dupfinder-linux-x86_64
# 移动到 PATH 目录
sudo mv dupfinder-linux-x86_64 /usr/local/bin/dupfinder
方式 3:从源码编译
bash
# 克隆仓库
git clone https://github.com/Waitfish/dupfinder.git
cd dupfinder
# 编译(Release 模式)
cargo build --release
# 安装
sudo cp target/release/dupfinder /usr/local/bin/
验证安装:
bash
dupfinder --version
dupfinder --help
🚀 使用方法
基本使用
1. 扫描当前目录
bash
# 递归扫描当前目录及所有子目录(默认)
dupfinder
# 或指定目录
dupfinder ~/Downloads
输出示例:
🔍 DupFinder - 重复文件查找工具
📂 扫描路径: /home/user/Downloads
🔄 递归模式: 开启
🔎 开始扫描 1234 个文件...
======================================================================
📊 发现 3 组重复文件
======================================================================
组 1:
/home/user/Downloads/photo1.jpg
/home/user/Downloads/backup/photo1.jpg
组 2:
/home/user/Downloads/video.mp4
/home/user/Downloads/copy_video.mp4
/home/user/Downloads/video_backup.mp4
======================================================================
📈 统计信息:
总重复文件数: 5
可删除文件数: 3 (保留每组 1 个)
======================================================================
2. 显示详细信息
bash
dupfinder -v -S ~/Downloads
参数说明:
-v或--verbose:显示 4 层验证的详细过程-S或--size:显示文件大小和可节省空间
输出示例:
🔍 第 1 层:按文件大小分组...
✓ 找到 15 组可能重复的文件(50 个文件)
🔍 第 2 层:计算部分内容哈希...
✓ 检查了 50 个文件,找到 8 组部分哈希相同(20 个文件)
🔍 第 3 层:计算完整文件 MD5...
✓ 检查了 20 个文件,找到 5 组完整 MD5 相同(15 个文件)
🔍 第 4 层:逐字节比较验证...
↪ 跳过硬链接: file1 <-> file1_link
✓ 进行了 10 次字节比较,确认 5 组完全重复(15 个文件)
组 1:
文件大小: 1.5 MB
/home/user/Downloads/photo1.jpg
/home/user/Downloads/photo2.jpg
可节省空间: 10.5 MB (10485760 bytes)
3. 只扫描当前目录(不递归)
bash
dupfinder -n ~/Downloads
参数 -n 或 --no-recursive 表示不递归扫描子目录。
4. 使用相对路径显示
bash
dupfinder -R ~/project
参数 -R 或 --relative 显示相对路径,方便查看项目结构。
高级功能
1. 导出 JSON 报告
bash
dupfinder ~/Downloads --json report.json
使用 jq 解析 JSON:
bash
# 查看统计信息
cat report.json | jq '.statistics'
# 查看可节省空间
cat report.json | jq '.statistics.potential_space_savings'
# 查看所有重复组
cat report.json | jq '.duplicate_groups[]'
Python 处理示例:
python
import json
with open('report.json') as f:
data = json.load(f)
print(f"扫描路径: {data['scan_info']['base_path']}")
print(f"重复组数: {data['scan_info']['total_groups']}")
print(f"可节省空间: {data['statistics']['potential_space_savings'] / 1024 / 1024:.2f} MB")
for group in data['duplicate_groups']:
print(f"\n组 {group['group_id']}:")
for file in group['files']:
print(f" - {file['path']}")
2. 生成删除脚本
bash
# 生成删除脚本
dupfinder ~/Downloads --delete-script delete_dups.sh
# 查看脚本内容
cat delete_dups.sh
# 执行删除(需要确认)
bash delete_dups.sh
执行效果:
⚠️ 警告: 即将删除重复文件!
扫描路径: /home/user/Downloads
重复组数: 3
将删除文件数: 5
可节省空间: 10.5 MB
确认要继续吗? (yes/no): yes
删除: /home/user/Downloads/photo_copy.jpg
删除: /home/user/Downloads/video_backup.mp4
...
✅ 成功删除: 5 个文件
💾 节省空间: 10.50MB
3. 同时生成 JSON 和删除脚本
bash
dupfinder -v -S ~/Downloads \
--json report.json \
--delete-script delete_dups.sh
这样可以先查看 JSON 报告,再决定是否执行删除。
完整参数列表
| 参数 | 简写 | 说明 | 默认值 |
|---|---|---|---|
<path> |
- | 扫描目录 | . (当前目录) |
--recursive |
-r |
递归扫描 | 开启 |
--no-recursive |
-n |
不递归 | - |
--verbose |
-v |
详细模式 | 关闭 |
--size |
-S |
显示大小 | 关闭 |
--relative |
-R |
相对路径 | 关闭 |
--hardlinks |
-H |
包含硬链接 | 关闭 |
--json <FILE> |
- | JSON 输出 | - |
--delete-script <FILE> |
- | 生成删除脚本 | - |
🎯 实际应用场景
场景 1:清理下载文件夹
bash
# 查看可以删除多少重复文件
dupfinder -S ~/Downloads
# 生成删除脚本
dupfinder ~/Downloads --delete-script clean_downloads.sh
# 检查并执行
bash clean_downloads.sh
场景 2:代码仓库去重
bash
cd ~/my-project
# 使用相对路径查看
dupfinder -R .
# 导出报告
dupfinder . --json dup_report.json
场景 3:备份文件检查
bash
# 详细模式查看验证过程
dupfinder -v ~/backup
# 同时生成报告和删除脚本
dupfinder ~/backup --json backup_report.json --delete-script clean_backup.sh
场景 4:CI/CD 集成
bash
#!/bin/bash
# 在 CI 中检查重复文件
dupfinder . --json dup_report.json
# 解析 JSON
deletable=$(jq '.statistics.deletable_files' dup_report.json)
if [ "$deletable" -gt 0 ]; then
echo "⚠️ 发现 $deletable 个重复文件,请清理"
jq '.duplicate_groups[]' dup_report.json
exit 1
fi
echo "✅ 未发现重复文件"
场景 5:定期清理任务
bash
# 创建清理脚本 weekly_cleanup.sh
#!/bin/bash
dupfinder ~/Downloads --delete-script /tmp/cleanup.sh --json /tmp/report.json
# 发送报告邮件
mail -s "重复文件清理报告" user@example.com < /tmp/report.json
# 可选:自动执行(谨慎使用!)
# echo "yes" | bash /tmp/cleanup.sh
# 添加到 crontab(每周日凌晨 2 点)
# 0 2 * * 0 /home/user/weekly_cleanup.sh
🔧 技术实现
项目结构
dupfinder/
├── Cargo.toml # 项目配置和依赖
├── src/
│ └── main.rs # 主程序(803 行)
├── README.md # 项目文档
├── USAGE.md # 详细使用说明
├── CHEATSHEET.md # 快速参考
└── .github/workflows/ # CI/CD 配置
核心依赖
toml
[dependencies]
clap = { version = "4.4", features = ["derive"] } # 命令行参数解析
walkdir = "2.4" # 目录遍历
md5 = "0.7" # MD5 哈希计算
colored = "2.1" # 彩色输出
same-file = "1.0" # 硬链接检测
serde = { version = "1.0", features = ["derive"] } # JSON 序列化
serde_json = "1.0" # JSON 支持
chrono = "0.4" # 时间处理
关键数据结构
rust
#[derive(Debug, Clone, Serialize, Deserialize)]
struct FileInfo {
path: PathBuf, // 文件路径
size: u64, // 文件大小
partial_hash: Option<String>, // 部分哈希(8KB)
full_hash: Option<String>, // 完整 MD5
}
struct DupFinder {
verbose: bool, // 详细模式
show_size: bool, // 显示大小
include_hardlinks: bool, // 包含硬链接
relative_path: bool, // 相对路径
base_path: PathBuf, // 基准路径
}
性能优化
- 分层筛选:大部分文件在前 1-2 层就被排除
- 按需计算:只对潜在重复文件计算哈希
- 缓冲读取:使用 8KB 缓冲区减少 I/O
- 编译优化 :使用
opt-level = "z"和lto = true
Cargo.toml 优化配置:
toml
[profile.release]
strip = true # 去掉符号表
opt-level = "z" # 优化体积
lto = true # 链接时优化
codegen-units = 1 # 增加优化机会
最终二进制大小:758KB(优化后)
📊 性能对比
测试环境:1000 个文件,总大小 500MB
| 工具 | 时间 | 准确性 | 功能 |
|---|---|---|---|
| dupfinder | 2.3s | 100% | JSON、删除脚本、彩色输出 |
| fdupes | 2.5s | 100% | 交互式删除 |
| rdfind | 1.8s | 99.9% | 自动删除 |
| 纯 MD5 | 3.2s | 99.9% | - |
🆚 与其他工具对比
| 特性 | dupfinder | fdupes | rdfind |
|---|---|---|---|
| 语言 | Rust 🦀 | C | C++ |
| 4 层验证 | ✅ | ✅ | ❌ |
| JSON 输出 | ✅ | ❌ | ❌ |
| 删除脚本 | ✅ | ❌ | ✅ (自动) |
| 彩色输出 | ✅ | ❌ | ❌ |
| 硬链接检测 | ✅ | ✅ | ✅ |
| 跨平台 | ✅ | ✅ | Linux |
| 二进制大小 | 758KB | ~50KB | ~100KB |
DupFinder 的优势:
- ✅ 唯一支持 JSON 输出的工具
- ✅ 生成安全的删除脚本(可编辑、需确认)
- ✅ 现代化的彩色界面
- ✅ 完整的文档和示例
💡 Rust 学习心得
作为一个 Rust 学习项目,DupFinder 让我深入理解了:
1. 所有权和借用
rust
// 借用路径,不获取所有权
fn calculate_md5(&self, path: &Path) -> io::Result<String> {
let mut file = File::open(path)?; // path 是借用的
// ...
}
2. 错误处理
rust
// Result<T, E> 强制处理错误
fn find_duplicates(&self, root: &Path) -> Vec<Vec<FileInfo>> {
match fs::metadata(path) {
Ok(metadata) => { /* 处理 */ },
Err(e) => { /* 错误处理 */ }
}
}
3. 迭代器和函数式编程
rust
// filter_map, map 等零成本抽象
let paths: Vec<_> = WalkDir::new(root)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
.map(|e| e.path().to_path_buf())
.collect();
4. 序列化
rust
// 使用 serde 自动序列化
#[derive(Serialize, Deserialize)]
struct FileInfo {
path: PathBuf,
size: u64,
}
let json = serde_json::to_string_pretty(&report)?;
📝 总结
DupFinder 是一个功能完整、性能优异的重复文件查找工具,特别适合:
✅ 需要自动化处理的场景(JSON 输出)
✅ 需要安全审查的场景(删除脚本)
✅ 需要跨平台支持的场景
✅ 追求准确性的场景(4 层验证)
下一步计划
- 交互式删除模式
- 并行处理大文件
- 进度条显示
- 更多哈希算法(SHA256, xxHash)
- CSV 输出格式
项目链接
- GitHub: https://github.com/Waitfish/dupfinder
- crates.io: https://crates.io/crates/dupfinder
- 安装 :
cargo install dupfinder
欢迎大家试用并提出建议!如果觉得有用,请给个 ⭐ Star!
🙏 参考资料
关注我,了解更多 Rust 项目实践!
本文首发于 CSDN,转载请注明出处。
标签 : Rust CLI 重复文件 文件管理 开源项目