.NET CORE下最快比较两个文件内容是否相同的方法

最近项目有个需求,需要比较两个任意大小文件的内容是否相同,要求如下:

  1. 项目是.NET CORE,所以使用C#进行编写比较方法

  2. 文件大小任意,所以不能将文件内容全部读入到内存中进行比较(更专业点说,需要使用非缓存的比较方式)

  3. 不依赖第三方库

  4. 越快越好

为了选出最优的解决方案,我搭建了一个简单的命令行工程,准备了两个大小为912MB的文件,并且这两个文件内容完全相同.在本文的最后,你可以看到该工程的Main方法的代码.

下面我们开始尝试各个比较方法,选出最优的解决方案:

比较两个文件是否完全相同,首先想到的是用哈希算法(如MD5,SHA)算出两个文件的哈希值,然后进行比较.

废话少说,撸起袖子写一个MD5比较方法:

640?wx_fmt=png

比较结果:

耗时5.79秒,感觉还不错.然而,这是最佳的解决方案吗?

其实我们仔细想一下,答案应该是否定的.

因为任何哈希算法本质上都是对字节进行一定的计算,而计算过程是要消耗时间的.

很多下载网站上提供了下载文件的哈希值,那是因为下载的源文件本身不会改变,只需要计算一次源文件的哈希值,提供给用户验证即可.

而我们的需求中,两个文件都是不固定的,那么每次都要计算两个文件的哈希值,就不太合适了.

所以,哈希比较这个方案被PASS.

这种求算法最优解的问题,我以往的经验是: 去stackoverflow查找 :)

经过我的艰苦努力,找到了一个非常切题的答案: How to compare 2 files fast using .NET?

得赞最多一个答案,将代码改造了一下放入工程中:

640?wx_fmt=png

该方法基本的原理是循环读取两个文件,每次读取8个字节,转换为Int64,再进行数值比较.那么效率如何呢?

Method: CompareByToInt64, Identical: True. Elapsed: 00:00:08.0918099

什么?8秒!竟然比MD5还慢?这不是SO得赞最多的答案吗,怎么会这样?

其实分析一下不难想到原因,因为每次只读取8个字节,程序频繁的进行IO操作,导致性能低下.看来SO上的答案也不能迷信啊!

那么优化的方向就变为了如何减少IO操作带来的损耗.

既然每次8个字节太少了,我们定义一个大一些的字节数组,比如1024个字节.每次读取1024个字节到数组中,然后进行字节数组的比较.

但是这样又带来一个新问题,就是如何快速比较两个字节数组是否相同?

我首先想到的是在MD5方法中用过的----将字节数组转换成字符串进行比较:

640?wx_fmt=png

结果:

Method: CompareByString, Identical: True. Elapsed: 00:00:07.8088732

耗时也接近8秒,比上一个方法强不了多少.

分析一下原因,在每次循环中,字符串的转换是一个非常耗时的操作.那么有没有不进行类型转换的字节数组比较方法呢?

我想到了LINQ中有一个比较序列的方法SequenceEqual,我们尝试使用该方法比较:

640?wx_fmt=png

结果:

Method: CompareBySequenceEqual, Identical: True. Elapsed: 00:00:08.2174360

竟然比前两个都要慢(实际这也是所有方案中最慢的一个),LINQ的SequenceEqual看来不是为了效率而生.

那么我们不用那些花哨的功能,回归质朴,老实儿的使用while循环比较字节数组怎么样呢?

640?wx_fmt=png

结果是....

Method: CompareByByteArry, Identical: True. Elapsed: 00:00:01.5356821

1.53秒!大突破!看来有时候看起来笨拙的方法反而效果更好!

试验到此,比较两个900多MB的文件耗时1.5秒左右,读者对于该方法是否满意呢?

No!我不满意!我相信通过努力,一定会找到更快的方法的!

同样.NET CORE也在为了编写高性能代码而不断的优化中.

那么,我们如何继续优化我们的代码呢?

我突然想到在C# 7.2中加入的一个新的值类型: Span<T>,它用来代表一段连续的内存区域,并提供一系列可操作该区域的方法.

对于我们的需求,因为我们不会更改数组的值,所以可以使用另外一个只读的类型ReadOnlySpan<T>追求更高的效率.

修改代码,使用ReadOnlySpan<T>:

640?wx_fmt=png

核心是用来比较的SequenceEqual方法,该方法是ReadOnlySpan的一个扩展方法,要注意它只是方法名与LINQ中一样,实现完全不同.
那么该方法的表现如何呢?

Method: CompareByReadOnlySpan, Identical: True. Elapsed: 00:00:00.9287703

不 到 一 秒!

相对上一个已经不错的结果,速度提高了差不多40%!

对此结果,我个人觉得已经很满意了,如果各位有更快的方法,请不吝赐教,我非常欢迎!

关于Span<T>结构类型,各位读者如有兴趣,可浏览该文章,该文有非常详细的介绍.

后记

  • 文中的代码只是出于实验性质,实际应用中仍可以继续细节上的优化, 如:

  1. 如两个文件大小不同,直接返回false

  2. 如果两个文件路径相同,直接返回true

  3. ...

试验工程的Main方法源码:

640?wx_fmt=png

原文地址:https://www.cnblogs.com/waku/p/11069214.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 
640?wx_fmt=jpeg


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/315340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

牛客挑战赛47 A 一道GCD问题

牛客挑战赛47 A 一道GCD问题 思路参考牛客上的题解&#xff1a; 根据多维的更相减损术得gcd(x,y,z)gcd(x,y−x,z−y)得 gcd(a1k,a2k,a3k…,ank)gcd(a1k,a2-a1,a3-a2…)gcd(a1k,a2k,a3k…,ank)gcd(a1k,a2−a1,a3−a2…) 我们很容易可以求得等式右边的值为g我们很容易可以求得等…

Codeforces Round #715 (Div. 2) D. Binary Literature 构造

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你个nnn和三个长度为n∗2n*2n∗2的串&#xff0c;让你构造一个长度≤n∗3\le n*3≤n∗3的串&#xff0c;使其子序列包含至少两个给定串。 思路&#xff1a; 先考虑如果没有长度限制&#xff0c;那么我们…

[译]试用新的System.Text.Json API

译注尝试新的System.Text.Json API对于.NET Core 3.0&#xff0c;我们 提供了一个名为System.Text.Json的全新命名空间 &#xff0c;支持读取器/写入器&#xff0c;文档对象模型&#xff08;DOM&#xff09;和序列化。在这篇博文中&#xff0c;我告诉你为什么我们建造它&#x…

牛客挑战赛47 C 条件(Floyd bitset优化)

牛客挑战赛47 C 条件 思路&#xff1a;首先我们要两个图&#xff0c;一个是一定能到达的&#xff0c;一个是可能到达的&#xff0c;如果我们使用floyd (n^3)就有可能会超时&#xff0c;因为只要求询问能否到达&#xff0c;所以权值只有0和1&#xff0c;那我们可以使用bitset来…

Educational Codeforces Round 81 (Rated for Div. 2) C. Obtain The String 序列自动机

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你两个串s,ts,ts,t&#xff0c;每次可以取sss串的一个子序列&#xff0c;问你最少取多少次子序列&#xff0c;将这些子序列拼起来能得到ttt。 思路&#xff1a; 发现我题解里面没写过序列自动机&#xf…

牛客练习赛75 D 减数游戏(队列优化(需要取模的)堆)

牛客练习赛75 D 减数游戏 思路:写一下式子可以发每次选择最小的两个数进行操作&#xff0c;最后得到的答案会是最大的&#xff0c;那我们可以将它放进一个最小堆中来维护&#xff0c;但是里面的数是需要取模的&#xff0c;当它取模的时候&#xff0c;将会变小。那我们可以用一…

C#规范整理·资源管理和序列化

源管理&#xff08;尤其是内存回收&#xff09;曾经是程序员的噩梦&#xff0c;不过在.NET平台上这个噩梦似乎已经不复存在。CLR在后台为垃圾回收做了很多事情&#xff0c;使得我们现在谈起在.NET上进行开发时&#xff0c;都会说还是new一个对象吧&#xff01;回收&#xff1f;…

Codeforces Round #615 (Div. 3) A-F

传送门 这场比较简单&#xff0c;简单的题就不说题意了。 A. 问加nnn个数&#xff0c;能否使a,b,ca,b,ca,b,c相等。 直接先加到相等再看看模333是否为000即可。 //#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #incl…

使用Elasticsearch 构建 .NET 企业级搜索

最近几年出现的云计算为组织和用户带来了福音。组织对客户的了解达到前所未有的透彻&#xff0c;并能够采用个性化通信锁定客户。用户几乎可以随时随地获取其数据&#xff0c;使其更加易于访问和使用。为了存储所有这些数据&#xff0c;大型数据中心遍布全世界。但是&#xff0…

牛客练习赛73 D 离别(线段树+右端点排序离线查询)

牛客练习赛73 D 离别 思路: 对于每一个固定的右端点i&#xff0c;我们都找到一个区间&#xff08;l,r&#xff09;使得区间中的点为左端点时 里面最大的的种数为k。 这个可以用队列或者vector来维护。 然后我们对于q个查询&#xff0c;安装r从小到大排序。 开始遍历&#xff0…

Codeforces Round #617 (Div. 3) F. Berland Beauty 思维

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给定一棵树&#xff0c;再给定若干两点最短路之间边权的最小值&#xff0c;让你给树的边权赋值&#xff0c;使得满足给定的条件&#xff0c;如果不存在输出−1-1−1。 思路&#xff1a; 观察一个性质&…

书籍推荐:《More Effective C#》

很多年前看过Bill Wagner的《Effective C#》第一版&#xff0c;涵盖了C#2.0相关语言特性的最佳实践&#xff0c;教我们怎样更优雅地去编写C#代码&#xff0c;当时觉得受益匪浅。最近拿到了《More Effective C#》第二版&#xff0c;目前看了大概三分之二&#xff0c;让我对C#的的…

Codeforces Round #717 (Div. 2) D(倍增dp)

Codeforces Round #717 (Div. 2) D 题意:n个数 q个询问&#xff0c;每一个询问有l和r&#xff0c;问你l到r这段区间中最少能分成几段&#xff0c;每一段中的数都是互质的。 思路&#xff1a;首先预处理出每一个点向左走最多能走多远&#xff0c;可以分解质因数来找&#xff0c…

使用 docker 部署常用的开发环境

使用 docker 部署常用的开发环境Intro前段时间电脑之前返厂修了&#xff0c;所有的软件都要重新装一遍&#xff0c;很麻烦&#xff0c;既然用了 docker 有些环境就直接用 docker 部署了&#xff0c;免去了还要再下载软件重新安装的麻烦。部署 SqlServerdocker 部署 SqlServer 2…

Codeforces Round #617 (Div. 3) E2. String Coloring (hard version) 思维 + dp + Dilworth定理

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 让你给一个串染色&#xff0c;不同颜色且相邻的一对字符可以互换位置&#xff0c;用最少的颜色&#xff0c;使交换后这个字符串字典序最小。 思路&#xff1a; 考虑将字符串分成若干个非递减的子序列&…

Codeforces Round #716 (Div. 2) D(随机算法)

Codeforces Round #716 (Div. 2) D 题意:区间查询&#xff0c;问区间最少能分成几部分使得最多的数不超过总数的一半 向上取整。 思路:找到区间的总数s&#xff0c;如果不超过一半的话就是一部分。超过一半的话&#xff0c;那我们只要考虑超过一半的那一个数怎么组合&#xff…

Codeforces Round #716 (Div. 2) D. Cut and Stick 主席树 + 思维

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你个长为nnn的数组aaa&#xff0c;定义好的区间为这个区间中每个数出现的次数≤⌈n2⌉\le \left \lceil \frac{n}{2} \right \rceil≤⌈2n​⌉&#xff0c;定义划分为将这个区间的若干个子序列拿出来构成若…

如何从现在开始写博客?

在前不久知名博主《纯洁的微笑》在博客园分享了他写博客的心得&#xff0c;获得了读者圈的广泛共鸣&#xff0c;同时也引起了一些老生常谈的争议&#xff0c;这样的讨论在我们长沙.NET技术社区内部也经常发生。1、写博客的好处在《软技能代码之外的生存指南》这本书中&#xff…

牛客挑战赛30 C 小G砍树 换根dp+组合

链接&#xff1a;https://ac.nowcoder.com/acm/contest/18072/E 题目&#xff1a;给你一棵n个节点的带标号无根树。每次&#xff0c;你可以选择一个度数为1的节点并将它从树上移除。问总共有多少种不同的方式能将这棵树删到只剩 1 个点。两种方式不同当且仅当至少有一步被删除的…

换根dp求树所有节点的最小深度

链接&#xff1a;https://ac.nowcoder.com/acm/contest/18072/A 牛妹有一张连通图&#xff0c;由n个点和n-1条边构成&#xff0c;也就是说这是一棵树&#xff0c;牛妹可以任意选择一个点为根&#xff0c;根的深度为0&#xff0c;对于任意一个非根的点&#xff0c;我们将他到根节…