设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间01 现在时间01 缓存数据 当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

查看: 891|回复: 2

.NET根据文件的哈希值筛选重复文件的实现思路

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:220
  • 打卡月天数:0
  • 打卡总奖励:3241
  • 最近打卡:2025-09-25 12:32:06
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
441
主题
396
精华
0
金钱
4537
积分
885
注册时间
2023-1-6
最后登录
2025-9-25

发表于 2025-6-1 05:30:31 | 显示全部楼层 |阅读模式

如题。先介绍下概念。

Q1. 文件的哈希值是什么?

文件的哈希值是通过特定的哈希算法对文件内容进行计算后得到的固定长度的字符串(通常由数字和字母组成),它具有以下特点和相关信息:

  • 哈希算法:常见的用于计算文件哈希值的算法包括 MD5、SHA-1、SHA-256、SHA-512 等。不同算法的计算方式和生成的哈希值长度不同。例如,MD5 算法生成的哈希值是 128 位(通常以 32 个十六进制字符表示),SHA-256 算法生成的哈希值是 256 位(以 64 个十六进制字符表示) 。
  • 唯一性:理论上,不同内容的文件经过哈希算法计算后,应该得到不同的哈希值。这意味着如果两个文件的哈希值相同,那么它们的内容很可能是完全一样的(虽然存在极小概率的哈希碰撞,即不同内容产生相同哈希值,但这种情况非常罕见)。例如,在文件传输过程中,接收方可以计算接收到的文件的哈希值,并与发送方提供的原始文件哈希值进行比较,以验证文件在传输过程中是否完整无损,没有被篡改。
  • 固定长度:无论文件的大小和内容如何,使用特定哈希算法计算得到的哈希值长度是固定的。例如,无论一个文本文件是几 KB 还是几 MB,使用 SHA-256 算法计算出的哈希值始终是 256 位。
  • 不可逆性:哈希计算是一种单向操作,即可以通过文件内容计算出哈希值,但无法从哈希值反向推导出原始的文件内容。这使得哈希值在数据存储和安全验证等方面具有重要作用,比如在存储用户密码时,通常存储的是密码的哈希值,即使数据库被攻击,攻击者也难以从哈希值还原出原始密码。

哈希值在文件验证、数据完整性检查、文件去重、密码存储等众多领域都有广泛应用,是确保数据一致性和安全性的重要手段之一。

Q2. 比如一个文件 有1G大小,那么它的哈希值会多大?

文件哈希值的大小与文件本身的大小无关,而是由所使用的哈希算法决定。

常见的哈希算法及其生成的哈希值大小如下:

  • MD5 算法:生成 128 位(16 字节)的哈希值,通常以 32 个十六进制字符表示。例如:
    1. d41d8cd98f00b204e9800998ecf8427e
    复制代码
     ,无论原文件是 1 字节还是 1GB 甚至更大,使用 MD5 算法计算出的哈希值固定是 128 位。
  • SHA-1 算法:产生 160 位(20 字节)的哈希值,一般以 40 个十六进制字符呈现。比如:
    1. da39a3ee5e6b4b0d3255bfef95601890afd80709
    复制代码
     ,不管文件大小怎样变化,SHA-1 算法得到的哈希值长度不变。SHA-256 算法:输出 256 位(32 字节)的哈希值,以 64 个十六进制字符展示。例如:
    1. e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    复制代码
     ,即使是 1GB 的大文件,其 SHA-256 哈希值依然是 256 位。
  • SHA-512 算法:生成 512 位(64 字节)的哈希值,用 128 个十六进制字符表示。如:
    1. cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
    复制代码
     ,同样不受文件大小影响。

所以,一个 1GB 大小的文件,其哈希值的大小取决于选择的哈希算法,而不是文件自身的体积大小。

需求:客户有200+份文件来源于不同的三方平台,但是客户不确定是否有重复文件。可能来源不同但是文件相同。客户希望筛出这些重复文件。供用户搜索用,这样用户就只会搜出唯一的文件结果,而不是来源于不同渠道的相同文件。

实现思路:

先获取所有文件的大小,并按照大小group by,这样相同大小的文件就会在一组。文件大小不同一定不属于相同文件,文件大小相同有可能属于相同文件,也有可能是不同的文件刚好大小相等。按照这方式,遍历所有相同大小的组。比对哈希值。文件大小不同的就不用比较了。肯定不是相同文件。

/*
代码说明
FindDuplicateFilesGrouped 方法:
首先遍历传入的文件路径数组,将每个文件的信息(Id、FileName、FileSize)封装到 FileInfoEntity 对象中,并添加到 fileInfos 列表。
接着按文件大小对 fileInfos 进行分组,得到 sizeGroups。
针对每个大小组,计算组内每个文件的哈希值,把具有相同哈希值的文件存到 hashGroups 字典里。
最后,将 hashGroups 中包含多个文件的组添加到 duplicateFileGroups 列表,该列表即为最终按组返回的重复文件结果。
通过这种方式,就能方便地找出所有重复文件,并将它们按组分类返回。
*/

FileComparisonTool.cs

  1. //FileComparisonTool.cs
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Security.Cryptography;
  9. namespace ConsoleApp1_CompareFiles
  10. {
  11. // 文件实体类
  12. public class FileInfoEntity
  13. {
  14. public Guid Id { get; set; }
  15. public MemoryStream Stream { get; set; }
  16. public string FileName { get; set; }
  17. public long FileSize { get; set; }
  18. }
  19. // 文件比较工具类
  20. public class FileComparisonTool
  21. {
  22. public static string[] GetAllFilesInFolder(string folderPath)
  23. {
  24. try
  25. {
  26. // 获取当前文件夹下的所有文件
  27. string[] files = Directory.GetFiles(folderPath);
  28. // 获取当前文件夹下的所有子文件夹
  29. string[] subFolders = Directory.GetDirectories(folderPath);
  30. foreach (string subFolder in subFolders)
  31. {
  32. // 递归调用获取子文件夹下的所有文件
  33. string[] subFiles = GetAllFilesInFolder(subFolder);
  34. files = files.Concat(subFiles).ToArray();
  35. }
  36. return files;
  37. }
  38. catch (Exception ex)
  39. {
  40. Console.WriteLine($"发生错误: {ex.Message}");
  41. return new string[0];
  42. }
  43. }
  44. // 计算文件哈希值
  45. private static string CalculateHash(Stream stream)
  46. {
  47. using (SHA256 sha256 = SHA256.Create())
  48. {
  49. byte[] hashBytes = sha256.ComputeHash(stream);
  50. return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
  51. }
  52. }
  53. // 入参是两个文件流,比较两个文件
  54. public static bool CompareFiles(Stream stream1, Stream stream2)
  55. {
  56. stream1.Position = 0;
  57. stream2.Position = 0;
  58. string hash1 = CalculateHash(stream1);
  59. string hash2 = CalculateHash(stream2);
  60. return hash1 == hash2;
  61. }
  62. // 入参是两个文件路径,比较两个文件
  63. public static bool CompareFiles(string filePath1, string filePath2)
  64. {
  65. using (FileStream stream1 = File.OpenRead(filePath1))
  66. using (FileStream stream2 = File.OpenRead(filePath2))
  67. {
  68. return CompareFiles(stream1, stream2);
  69. }
  70. }
  71. // 入参是文件路径的数组,找出重复文件
  72. public static List<FileInfoEntity> FindDuplicateFiles(string[] filePaths)
  73. {
  74. var fileInfos = new List<FileInfoEntity>();
  75. foreach (var filePath in filePaths)
  76. {
  77. var fileInfo = new FileInfo(filePath);
  78. fileInfos.Add(new FileInfoEntity
  79. {
  80. Id = Guid.NewGuid(),
  81. FileName = filePath,
  82. FileSize = fileInfo.Length
  83. });
  84. }
  85. var groups = fileInfos.GroupBy(f => f.FileSize);
  86. var duplicateFiles = new List<FileInfoEntity>();
  87. foreach (var group in groups)
  88. {
  89. if (group.Count() > 1)
  90. {
  91. var hashes = new Dictionary<string, FileInfoEntity>();
  92. foreach (var file in group)
  93. {
  94. using (FileStream stream = File.OpenRead(file.FileName))
  95. {
  96. string hash = CalculateHash(stream);
  97. if (hashes.ContainsKey(hash))
  98. {
  99. if (!duplicateFiles.Contains(hashes[hash]))
  100. {
  101. duplicateFiles.Add(hashes[hash]);
  102. }
  103. duplicateFiles.Add(file);
  104. }
  105. else
  106. {
  107. hashes[hash] = file;
  108. }
  109. }
  110. }
  111. }
  112. }
  113. return duplicateFiles;
  114. }
  115. /*
  116. 代码说明
  117. FindDuplicateFilesGrouped 方法:
  118. 首先遍历传入的文件路径数组,将每个文件的信息(Id、FileName、FileSize)封装到 FileInfoEntity 对象中,并添加到 fileInfos 列表。
  119. 接着按文件大小对 fileInfos 进行分组,得到 sizeGroups。
  120. 针对每个大小组,计算组内每个文件的哈希值,把具有相同哈希值的文件存到 hashGroups 字典里。
  121. 最后,将 hashGroups 中包含多个文件的组添加到 duplicateFileGroups 列表,该列表即为最终按组返回的重复文件结果。
  122. 通过这种方式,就能方便地找出所有重复文件,并将它们按组分类返回。
  123. */
  124. // 入参是文件路径数组,按组返回重复文件
  125. public static List<List<FileInfoEntity>> FindDuplicateFilesGrouped(string[] filePaths)
  126. {
  127. var fileInfos = new List<FileInfoEntity>();
  128. foreach (var filePath in filePaths)
  129. {
  130. var fileInfo = new FileInfo(filePath);
  131. fileInfos.Add(new FileInfoEntity
  132. {
  133. Id = Guid.NewGuid(),
  134. FileName = filePath,
  135. FileSize = fileInfo.Length
  136. });
  137. }
  138. var sizeGroups = fileInfos.GroupBy(f => f.FileSize);
  139. var duplicateFileGroups = new List<List<FileInfoEntity>>();
  140. foreach (var sizeGroup in sizeGroups)
  141. {
  142. if (sizeGroup.Count() > 1)
  143. {
  144. var hashGroups = new Dictionary<string, List<FileInfoEntity>>();
  145. foreach (var file in sizeGroup)
  146. {
  147. using (FileStream stream = File.OpenRead(file.FileName))
  148. {
  149. string hash = CalculateHash(stream);
  150. if (!hashGroups.ContainsKey(hash))
  151. {
  152. hashGroups[hash] = new List<FileInfoEntity>();
  153. }
  154. hashGroups[hash].Add(file);
  155. }
  156. }
  157. foreach (var hashGroup in hashGroups.Values)
  158. {
  159. if (hashGroup.Count > 1)
  160. {
  161. duplicateFileGroups.Add(hashGroup);
  162. }
  163. }
  164. }
  165. }
  166. return duplicateFileGroups;
  167. }
  168. }
  169. }
复制代码

//

  1. // Program.cs
  2. // See https://aka.ms/new-console-template for more information
  3. using ConsoleApp1_CompareFiles;
  4. Console.WriteLine("Hello, World!");
  5. string[] filePaths = {
  6. "C:\\Users\\Aa\\Desktop\\新建文件夹\\1.txt",
  7. "C:\\Users\\Aa\\Desktop\\新建文件夹\\2.txt",
  8. "C:\\Users\\Aa\\Desktop\\新建文件夹\\3.txt",
  9. "C:\\Users\\Aa\\Desktop\\新建文件夹\\4.xlsx",
  10. "C:\\Users\\Aa\\Desktop\\新建文件夹\\5.xlsx",
  11. "C:\\Users\\Aa\\Desktop\\新建文件夹\\6.docx",
  12. "C:\\Users\\Aa\\Desktop\\新建文件夹\\7.docx",
  13. "C:\\Users\\Aa\\Desktop\\新建文件夹\\8.jpeg",
  14. "C:\\Users\\Aa\\Desktop\\新建文件夹\\9.jpeg",
  15. "C:\\Users\\Aa\\Desktop\\新建文件夹\\捕获 - 副本.PNG",
  16. "C:\\Users\\Aa\\Desktop\\新建文件夹\\捕获.PNG",
  17. "C:\\Users\\Aa\\Desktop\\新建文件夹\\微信图片_20250221165428.png",
  18. };
  19. string folderPath = @"C:\Users\Aa\Desktop\新建文件夹";
  20. string[] allFiles = FileComparisonTool.GetAllFilesInFolder(folderPath);
  21. var duplicateFileGroups = FileComparisonTool.FindDuplicateFilesGrouped(allFiles);
  22. Console.WriteLine($"找到的重复文件组数量: {duplicateFileGroups.Count}");
  23. foreach (var group in duplicateFileGroups)
  24. {
  25. Console.WriteLine($"该组重复文件数量: {group.Count}");
  26. foreach (var file in group)
  27. {
  28. Console.WriteLine($" 文件 ID: {file.Id}, 文件名: {file.FileName}, 文件大小: {file.FileSize}");
  29. }
  30. }
复制代码

实现效果:

1.png

测试文件.txt文本的举例子。可以看到黄框和红框内的都属于相同文件。红框和黄框内的虽然字节数是一样的,相同大小会group by到一组。但是hash值肯定是不同的。

2.png

到此这篇关于.NET下根据文件的哈希值筛选重复文件的文章就介绍到这了,更多相关.net哈希值筛选重复文件内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:无名新人
  • 打卡总天数:2
  • 打卡月天数:0
  • 打卡总奖励:21
  • 最近打卡:2024-07-16 22:30:53
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
34
积分
6
注册时间
2023-11-30
最后登录
2024-7-16

发表于 2025-7-5 22:13:08 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
21
积分
22
注册时间
2022-12-28
最后登录
2022-12-28

发表于 5 天前 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表