用 C# WinForm 打造自己的文件扫描与 MD5 校验工具
前言
最近在工作中遇到了一个烦心事:我有好几个文件夹散落在硬盘各处,里面存放着大量文档、图片和备份文件,总容量超过 200GB。随着时间的推移,这些文件夹里产生了大量重复文件,不仅占用空间,还让我在查找资料时经常一头雾水。
我需要一个工具,能够指定多个文件夹,递归扫描所有子文件夹,计算每个文件的 MD5 值,找出重复文件,并且能够方便地将文件迁移到其他位置。找了一圈现成的软件,要么收费,要么功能不符合我的需求,于是我决定自己动手写一个。
今天我就来分享一下这个工具的完整开发过程,代码已经在我电脑上跑通了,效果还不错。
技术选型
我选择了 C# 和 WinForm。理由很简单:
- 开发效率高:拖拖控件就能搭出界面原型。
- 性能足够:处理几万个文件毫无压力。
- 部署方便:编译成一个 exe 就能跑。
核心功能设计
在动手写代码之前,我先梳理了一下需要实现的功能:
- 多文件夹管理:可以添加、删除要扫描的文件夹,支持拖拽添加。
- 递归扫描:自动扫描子文件夹中的所有文件。
- 唯一性标识:计算 MD5 值(可选 SHA256)。
- 重复文件检测:自动高亮 MD5 相同的文件。
- 文件列表展示:显示文件名、MD5、大小、路径等信息。
- 文件迁移:可以将选中的文件复制到目标文件夹,支持覆盖和自动重命名。
- 性能优化:大文件处理优化,支持取消扫描。
界面布局
我整体把界面分成两个区域:
右侧三分之二的区域为文件展示区域,左侧为选择文件夹,扫描文件等功能操作区域。
关键代码解析
1.文件信息模型
首先定义一个类来存储每个文件的信息:
csharp
public class FileInfoItem
{
public string FileName { get; set; }
public string MD5 { get; set; }
public string SHA256 { get; set; }
public string FileSize { get; set; }
public string FilePath { get; set; }
public long FileSizeBytes { get; set; }
public string MigrationStatus { get; set; } = "未迁移";
}
2.MD5 计算(大文件优化)
计算 MD5 时有个坑:如果直接读取整个文件到内存,遇到几个 GB 的大文件就会卡死甚至内存溢出。我的解决方案是使用缓冲读取:
csharp
private string CalculateMD5(string filePath)
{
using (var md5 = MD5.Create())
{
using (var stream = File.OpenRead(filePath))
{
// 对于大文件使用缓冲读取
if (stream.Length > 100 * 1024 * 1024) // 大于100MB
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
md5.TransformBlock(buffer, 0, bytesRead, null, 0);
}
md5.TransformFinalBlock(new byte[0], 0, 0);
return BitConverter.ToString(md5.Hash).Replace("-", "").ToUpper();
}
else
{
byte[] hash = md5.ComputeHash(stream);
return BitConverter.ToString(hash).Replace("-", "").ToUpper();
}
}
}
}
3.异步扫描 + 可取消操作
扫描过程可能很慢,不能让界面卡住。我用 async/await 加上 CancellationToken 来实现异步和可取消:
csharp
private async void btnScan_Click(object sender, EventArgs e)
{
cancellationTokenSource = new CancellationTokenSource();
try
{
await Task.Run(() => ScanFiles(cancellationTokenSource.Token));
}
catch (OperationCanceledException)
{
lblStatus.Text = "扫描已取消";
}
}
private void ScanFiles(CancellationToken cancellationToken)
{
foreach (string filePath in allFiles)
{
cancellationToken.ThrowIfCancellationRequested();
// 计算MD5...
}
}
4.重复文件检测
扫描完成后,按 MD5 分组就能找出重复文件:
csharp
private void HighlightDuplicateFiles()
{
var duplicates = fileList
.GroupBy(f => f.MD5)
.Where(g => g.Count() > 1 && !string.IsNullOrEmpty(g.Key))
.SelectMany(g => g)
.ToList();
foreach (DataGridViewRow row in dataGridViewFiles.Rows)
{
var item = row.DataBoundItem as FileInfoItem;
if (item != null && duplicates.Contains(item))
{
row.DefaultCellStyle.BackColor = Color.LightYellow;
}
}
}
5.文件迁移
迁移时我提供了三种冲突处理策略:覆盖、自动重命名、询问用户:
csharp
if (File.Exists(destFileName))
{
if (chkOverwriteExisting.Checked)
{
File.Copy(item.FilePath, destFileName, true);
}
else if (chkAutoRename.Checked)
{
// 自动生成不重复的文件名
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(item.FileName);
string extension = Path.GetExtension(item.FileName);
int counter = 1;
while (File.Exists(destFileName))
{
destFileName = Path.Combine(targetPath, $"{fileNameWithoutExt}_{counter}{extension}");
counter++;
}
File.Copy(item.FilePath, destFileName);
}
else
{
// 弹窗询问用户
var result = MessageBox.Show($"文件 {item.FileName} 已存在,是否覆盖?", "确认",
MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
// 处理用户选择...
}
}
使用体验
工具写好后,我拿自己的文件夹测试了一下:
- 扫描速度:10000 个文件(总共约 50GB),计算 MD5 耗时约 25 秒
- 重复文件检测:发现了 300 多个重复文件,都是我以前到处复制粘贴留下的
- 迁移功能:把重复文件整理到一个新文件夹,每天打开它删一批,硬盘空间多了接近 20GB
踩过的坑
- 开发过程中也遇到了一些问题:
- 无权限访问的文件夹:有些系统文件夹会抛出 UnauthorizedAccessException,用 try-catch 跳过就好
- 文件被占用:如果文件正在被其他程序打开,读取会失败,这时候可以给用户提示
- UI 更新跨线程:在异步任务中更新界面要用 Invoke,否则会报错
- 大文件内存问题:一开始直接 File.ReadAllBytes,扫描一个 4GB 的 ISO 文件直接内存爆炸,后来改成流式读取才解决
关于 MD5 的唯一性
有朋友问我:MD5 真的能保证文件唯一吗?
我的回答是:工程上够用,理论上有风险。MD5 的碰撞概率极低(2^128 种可能性),对于普通业务场景完全够用。但如果你处理的是安全敏感的文件(比如数字签名、法律证据),建议用 SHA256。
我在工具里预留了 SHA256 的选项,有需要可以勾上,不过计算时间会长一些。
后续可以改进的地方
- 增量扫描:记录已扫描文件的 MD5,下次只扫描新增或修改的文件
- 导出报告:将重复文件列表导出为 Excel 或 CSV
- 快速预览:双击文件直接在关联程序中打开
- 文件过滤:按扩展名、大小、修改时间过滤
- 并行计算:用多线程同时计算多个文件的 MD5,进一步提升速度
完整代码获取
完整的项目代码我已经整理好了,包含:
- Form1.cs - 主窗体逻辑
- Form1.Designer.cs - 界面布局
- Program.cs - 程序入口
- .csproj - 项目文件
需要的朋友可以在评论区留言,我会把代码发给大家。
写在最后
从需求分析到代码实现,这个工具断断续续写了两三天。虽然市面上有很多现成的重复文件查找工具,但自己写的用起来就是顺手 —— 想要什么功能随时加,不用看广告也不用付费。
如果你也有类似的需求,不妨试试自己动手写一个。C# + WinForm 真的是桌面小工具的快速开发利器,半天就能搭出原型,两天就能出一个能用的版本。
有什么问题欢迎在评论区交流!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)