《.NET 下最快比较两个文件内容是否相同》之我的看法验证

news2024/12/28 21:56:33

我对文件对比这一块还是比较感兴趣的,也想知道哪种方式性价比最高,效率最好,所以,根据这篇文章,我自己也自测一下,顺便留出自己对比的结果,供大佬们参考一二。

大致对比方案

我这边根据文章里的主要三个方案

  1. MD5
  2. 缓存长度读取比较
  3. 缓存长度读取(Span)比较
  4. Hash256
  5. CRC(最后补的)

新增了Hash256模式,原因是因为GitHub就是用Hash256来确定文件的唯一性的,所以,也想测试下它的性能到底如何。

又新增了CRC模式,后来才想起来的。

代码大致如下

挺简单的一个抽象工具类,方便增加相关的相同测试。
我也搜了OpenAi的建议和NewBing的建议,大致都是一样的建议。

根据建议和参考文章

抽象工具

public abstract class AFileCompare
{
    public AFileCompare(string name)
    {
        this.Name = name;
    }
    public string Name { get; set; }
    public bool Compare(string file1, string file2)
    {
        var result = false;
        Stopwatch stopwatch = Stopwatch.StartNew();
        if (Check(file1, file2))
        {
            result = CompareCore(file1, file2);
        }
        stopwatch.Stop();
        TimeSpan = stopwatch.Elapsed;
        return result;
    }
    public abstract bool CompareCore(string file1, string file2);
    public TimeSpan TimeSpan { get; set; }
    public bool Check(string file1, string file2)
    {
        if (file1 == file2)
        {
            return true;
        }
        if (new FileInfo(file1).Length == new FileInfo(file2).Length)
        {
            return true;
        }
        return false;
    }
    public override string ToString()
    {
        return $"{Name}耗时:{TimeSpan.TotalSeconds}秒";
    }
}

MD5工具

public class MD5Compare : AFileCompare
{
    public MD5Compare() : base("MD5 ")
    {
    }

    public override bool CompareCore(string file1, string file2)
    {
        using (var md5 = MD5.Create())
        {
            byte[] one, two;
            using (var fs1 = File.Open(file1, FileMode.Open))
            {
                // 以FileStream读取文件内容,计算HASH值
                one = md5.ComputeHash(fs1);
            }
            using (var fs2 = File.Open(file2, FileMode.Open))
            {
                // 以FileStream读取文件内容,计算HASH值
                two = md5.ComputeHash(fs2);
            }
            for (int i = 0; i < one.Length; i++)
            {
                if (one[i] != two[i])
                {
                    return false;
                }
            }
            return true;
        }
    }
}

Hash256

public class HashCompare : AFileCompare
{
    public HashCompare() : base("Hash256")
    {
    }

    public override bool CompareCore(string file1, string file2)
    {
        byte[] one, two;
        using (SHA1 mySHA1 = SHA1.Create())
        {
            using (FileStream stream = File.OpenRead(file1))
            {
                one = mySHA1.ComputeHash(stream);
            }
        }
        using (SHA1 mySHA1 = SHA1.Create())
        {
            using (FileStream stream = File.OpenRead(file2))
            {
                two = mySHA1.ComputeHash(stream);
            }
        }
        for (int i = 0; i < one.Length; i++)
        {
            if (one[i] != two[i])
            {
                return false;
            }
        }
        return true;
     }
}

缓存长度读取比较

public class FileSizeCompare : AFileCompare
{
    public FileSizeCompare() : base("FileSize_4096")
    {
    }

    public override bool CompareCore(string file1, string file2)
    {
        using (FileStream fs1 = new FileStream(file1, FileMode.Open))
        using (FileStream fs2 = new FileStream(file2, FileMode.Open))
        {
            byte[] buffer1 = new byte[4096];
            byte[] buffer2 = new byte[4096];

            int bytesRead1;
            int bytesRead2;

            do
            {
                bytesRead1 = fs1.Read(buffer1, 0, buffer1.Length);
                bytesRead2 = fs2.Read(buffer2, 0, buffer2.Length);

                if (bytesRead1 != bytesRead2)
                {
                    return false;
                }

                for (int i = 0; i < bytesRead1; i++)
                {
                    if (buffer1[i] != buffer2[i])
                    {
                        return false;
                    }
                }
            } while (bytesRead1 > 0);

            return true;
        }
    }
}

缓存长度读取(Span)比较

public class FileSizeCompare2 : AFileCompare
{
    public FileSizeCompare2() : base("FileSize_4096_Span")
    {
    }

    public override bool CompareCore(string file1, string file2)
    {
        using (FileStream fs1 = new FileStream(file1, FileMode.Open))
        using (FileStream fs2 = new FileStream(file2, FileMode.Open))
        {
            byte[] buffer1 = new byte[4096];
            byte[] buffer2 = new byte[4096];

            int bytesRead1;
            int bytesRead2;

            do
            {
                bytesRead1 = fs1.Read(buffer1, 0, buffer1.Length);
                bytesRead2 = fs2.Read(buffer2, 0, buffer2.Length);

                if (bytesRead1 != bytesRead2)
                {
                    return false;
                }

                if (!((ReadOnlySpan<byte>)buffer1).SequenceEqual((ReadOnlySpan<byte>)buffer2))
                {
                    return false;
                }
            } while (bytesRead1 > 0);

            return true;
        }
    }
}

CRC(补充)

public class CRCCompare : AFileCompare
{
    public CRCCompare() : base("CRC")
    {
    }
    public override bool CompareCore(string file1, string file2)
    {
        Crc32Algorithm crc32 = new Crc32Algorithm();
        byte[] one, two;
        using (var fs1 = File.Open(file1, FileMode.Open))
        {
            one = crc32.ComputeHash(fs1);
        }
        using (var fs2 = File.Open(file2, FileMode.Open))
        {
            two = crc32.ComputeHash(fs2);
        }
        for (int i = 0; i < one.Length; i++)
        {
            if (one[i] != two[i])
            {
                return false;
            }
        }
        return true;
    }
}

main 入口

static void Main(string[] args)
{
    var files = new List<(string name, string source, string target)>()
    {
        ("ubuntu_4.58 GB",@"E:\重装系统\ubuntu-22.04.2-desktop-amd64.iso",@"E:\重装系统\ubuntu-22.04.2-desktop-amd64 - 副本.iso"),
        ("Docker_523 MB",@"E:\重装系统\Docker Desktop Installer(1).exe",@"E:\重装系统\Docker Desktop Installer(1) - 副本.exe"),
        ("Postman_116 MB",@"E:\重装系统\Postman-win64-8.5.0-Setup.exe",@"E:\重装系统\Postman-win64-8.5.0-Setup - 副本.exe")
    };
    var list = new List<AFileCompare>();
    list.Add(new MD5Compare());
    list.Add(new HashCompare());
    list.Add(new FileSizeCompare());
    list.Add(new FileSizeCompare2());
    foreach ((string name, string source, string target) in files)
    {
        foreach (var item in list)
        {
            var result = item.Compare(source, target);
            Console.WriteLine($"{name} - {item.Name} 结果:{result} {item}");
        }
        Console.WriteLine();
    }
    Console.WriteLine("测试完毕");
    Console.ReadLine();
}

测试结果如下

主要是对3个文件,4.5G,500M,100M文件进行了测试,大概也能看出来点结果了。

测试1

测试2

测试3

CRC补充三次

第一次

第二次

第三次

结果对比

根据我分析的表大致可以看出来,五种方式,根据各种不同的文件对比方式,在文件大小不一样的情况下,差别还是挺大的,特别是在大文件的情况下。

文件越大,反而MD5和Hash效果会更好。
文件小于1G ?,FileSize_Span方式会更优,除了MD5,其他方式基本都差不多,CRC属于不上也不下。

虽然,环境的因素会有一定的影响,假设我这个就是客户的机器,那可能性也是存在的。

所以,在同一台机器上的多次测试也有存在的合理性。

那么,如果对性能很在意的话,可以根据文件大小与各种对比方法之间的关系,找到一个函数映射关系,从而找到一个最优的对比方法出来。

总结

还挺意外的,本来想验证这个Span方式为何快,却看到了另外问题点,出乎意料。

另外,也看到了Github采用Hash256在获取指纹上,速度还是相对稳定的。那么,用它来对比文件还是提取指纹应该是最佳之选(性能要求苛刻的,得自己搞模型求最佳函数映射关系)

还有其他的细节优化还没有验证,但是Span的方式是值得借鉴和学习的。

《.NET 下最快比较两个文件内容是否相同》参考地址

https://www.cnblogs.com/waku/p/11069214.html

代码地址

https://github.com/kesshei/FileCompare.git

https://gitee.com/kesshei/FileCompare.git

一键三连呦!,感谢大佬的支持,您的支持就是我的动力!

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

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

相关文章

循环队列(Ring Buffer)

背景&#xff1a; 最近在复习数据结构和算法&#xff0c;顺带刷刷题&#xff0c;虽然很长时间不刷题了但还是原来熟悉的味道&#xff0c;每一次重学都是加深了上一次的理解。本次我们看一下 循环队列(Ring Buffer)&#xff0c;C语言实现。 循环队列&#xff1a;首先 它是一个队…

chatgpt赋能python:Python安装好后怎么写代码?

Python安装好后怎么写代码&#xff1f; Python是一种高级编程语言&#xff0c;已成为众多开发者的首选工具。根据一些统计数据&#xff0c;Python排名全球第三的流行语言&#xff0c;已经成为Web开发、数据科学和人工智能领域的首选语言。如果您刚刚安装了Python&#xff0c;那…

【LeetCode全题库算法速练】6、N 字形变换

文章目录 一、题目&#x1f538;题目描述&#x1f538;样例1&#x1f538;样例2&#x1f538;样例3 二、代码参考 作者&#xff1a;KJ.JK &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &a…

YOLOv5/v7 添加注意力机制,30多种模块分析①,SE模块,SK模块

目录 一、注意力机制介绍1、什么是注意力机制&#xff1f;2、注意力机制的分类3、注意力机制的核心 二、SE模块1、SE模块的原理2、代码实例3、实验结果4、应用示例&#xff08;1&#xff09;在 models/yolo.py 文件中定义 SEModule 类&#xff0c;用于实现SE模块。&#xff08;…

pyautogui实现自动连接GP VPN

支线小小项目(pyautogui实现自动连接GP VPN) 用了pyautogui做了一个懒人小脚本&#xff0c;主要是在家上班&#xff0c;每天要连公司vpn, 然后还要等好久&#xff0c;公司用的GP(global protect) VPN, 长这个样子 主要问题每次点击connect后需要等他先出来windows NT的login认…

Web安全总结

目录 网站架构一般web服务器结构相比于传统的网络攻击&#xff0c;基于web的攻击有什么不同&#xff1f;HTTP协议HTTP响应拆分攻击HTTPS针对HTTPS协议的攻击那么如何保证证书的唯一性&#xff1f; HTTP会话Cookie和Session的关系HTTP会话攻击解决方案 Web访问中的隐私问题Web应…

【读书笔记】《贫穷的本质》- [印度] Abhijit Banerjee / [法] Esther Duflo

文章目录 前言第一章 再好好想想第一部分 生活案例第二章 饥饿人口已达到10亿&#xff1f;第三章 提高全球居民健康水平容易吗&#xff1f;第四章 全班最优 前言 扶贫政策方面充斥着会取得立竿见影的效果的泡沫&#xff0c;事实证明这一点儿也不奇怪。要想取得进展&#xff0c;…

sed:命令讲解一

sed的使用&#xff1a; sed的使用 一、sed1.定义&#xff1a;2.工作流程&#xff1a;读取&#xff0c;执行&#xff0c;显示。3.基本操作格式&#xff1a;4.sed操作符&#xff1a;5.扩展&#xff1a; 一、sed 1.定义&#xff1a; 一种流编辑器&#xff0c;会在编辑器处理数据…

浅谈发改委强化电力需求侧管理缓解电力系统峰值压力方案设计 安科瑞 许敏

摘要&#xff1a;近年来全国用电负荷特别是居民用电负荷的快速增长&#xff0c;全国范围内夏季、冬季用电负荷“双峰”特征日益突出&#xff0c;恶劣气候现象多发增加了电力安全供应的压力。具有随机性、波动性、间歇性特征的可再生能源大规模接入电网对电力系统的稳定性带来新…

MySQL 索引及查询优化总结

一个简单的对比测试 前面的案例中&#xff0c;c2c_zwdb.t_file_count表只有一个自增id&#xff0c;FFileName字段未加索引的sql执行情况如下&#xff1a; 在上图中&#xff0c;typeall&#xff0c;keynull&#xff0c;rows33777。该sql未使用索引&#xff0c;是一个效率非常低…

chatgpt赋能python:Python安装HanLP:一个强大的NLP工具

Python安装HanLP&#xff1a;一个强大的NLP工具 HanLP是一个基于Python编写的神经网络自然语言处理工具&#xff0c;它提供给我们强大的文本处理和分析能力。在这篇文章中&#xff0c;我们将介绍如何在Python中安装并使用HanLP工具。如果你是一个文本处理和分析的爱好者或者工…

chatgpt赋能python:Python安装到U盘——实现随时随地的编程

Python安装到U盘——实现随时随地的编程 Python是一种广泛使用的动态解释型编程语言&#xff0c;简单易学&#xff0c;适用性广泛&#xff0c;被广泛应用于数据分析、Web开发、人工智能等领域。想要充分发挥Python的优势&#xff0c;随时随地进行编程&#xff0c;我们可以将Py…

人工智能正迎来量子飞跃——

光子盒研究院 6月1日&#xff0c;量子计算领域的行业领导者IonQ公布了其应用量子计算机模拟人类认知的一项早期研究结果。这篇论文描述了世界上第一个公开的方法&#xff1a;研究团队已将一个基本的人类认知模型在量子硬件上运行&#xff0c;这为模仿人类思维方式的改进决策模型…

Day_42哈希表

目录 一. 关于哈希表 二. 如何实现哈希表 1. 散列函数 2. 散列表 3. 散列函数的构造方法 4. 处理冲突的方法 三. 代码实现 1. 构造函数构造哈希表 2. 哈希表的查找 四. 代码展示 五. 数据测试​编辑 六. 总结 一. 关于哈希表 在前面介绍的线性表的查找中,记录在表中的位置…

RabbitMQ入门案例之Simple简单模式

RabbitMQ入门案例之Simple简单模式 前言什么是Simple模式Simple模式操作RabbitMQ管理界面的部分介绍 前言 本文将介绍RabbitMQ的七种工作模式的第一种Simple模式的代码实现&#xff0c;编程工具使用的是IDEA&#xff0c;在RabbitMQ中的工作模式都是生产消费模型 生产者消费模型…

Android系统的Ashmem匿名共享内存子系统分析(4)- Ashmem子系统的 Java访问接口

声明 其实对于Android系统的Ashmem匿名共享内存系统早就有分析的想法&#xff0c;记得2019年6、7月份Mr.Deng离职期间约定一起对其进行研究的&#xff0c;但因为我个人问题没能实施这个计划&#xff0c;留下些许遗憾…文中参考了很多书籍及博客内容&#xff0c;可能涉及的比较…

【云原生】Docker镜像的创建

1.Dokcer镜像的创建 创建镜像有三种方法&#xff0c;分别为【基于已有镜像创建】、【基于本地模板创建】以及【基于Dockerfile创建】。 1.1 基于现有镜像创建 &#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改 docker run -it --name web centos:7 /…

2023年6月 国内大语言模型对比【国内模型正在崛起】

先说一下这个文章怎么来的。因为朋友问我大语言模型可以生成公务员面试回答不&#xff0c;我说可以啊。之前看文心有这个服务。我想最近好几个模型也没用了测一把&#xff01;结果&#xff01;大吃一惊&#xff01;我觉得我的三个傻孩子长大了&#xff01;&#xff08;chatglm1…

chatgpt赋能python:Python如何降低版本:提升代码兼容性与SEO效果

Python如何降低版本&#xff1a;提升代码兼容性与SEO效果 在大多数情况下&#xff0c;使用Python的最新版本是最好的选择。新版本通常提供更好的性能和更多的功能&#xff0c;同时也有更好的安全性和稳定性。然而&#xff0c;有些情况下&#xff0c;我们需要运行旧版本的Pytho…

chatgpt赋能python:Python字体如何调大?一篇全面的教程

Python字体如何调大&#xff1f;一篇全面的教程 什么是Python&#xff1f; Python是一种高级编程语言&#xff0c;一般被用于Web开发、数据分析和人工智能等领域。其编写简单、易读易学易维护&#xff0c;因此被广泛使用。 为什么要调大Python字体&#xff1f; 在Python编程…