C# 计算文件的MD5校验和

C# 计算文件的MD5校验和,c#,.net,hash,md5,C#,.net,Hash,Md5,我正在使用从PDF文件中读取文本。但是,有时我无法提取文本,因为PDF文件仅包含图像。我每天都下载相同的PDF文件,我想看看PDF是否被修改过。如果无法获取文本和修改日期,那么校验和是否是判断文件是否已更改的最可靠方法 如果是,请提供一些代码示例,因为我没有太多的密码学经验。使用以下代码非常简单: (我相信实际上使用的MD5实现不需要处理,但无论如何我还是会这样做的。) 之后如何比较结果取决于您;例如,您可以将字节数组转换为base64,或者直接比较字节。(请注意,数组不会覆盖Equals。使用

我正在使用从PDF文件中读取文本。但是,有时我无法提取文本,因为PDF文件仅包含图像。我每天都下载相同的PDF文件,我想看看PDF是否被修改过。如果无法获取文本和修改日期,那么校验和是否是判断文件是否已更改的最可靠方法

如果是,请提供一些代码示例,因为我没有太多的密码学经验。

使用以下代码非常简单:

(我相信实际上使用的MD5实现不需要处理,但无论如何我还是会这样做的。)

之后如何比较结果取决于您;例如,您可以将字节数组转换为base64,或者直接比较字节。(请注意,数组不会覆盖
Equals
。使用base64更容易正确,但如果您真的只对比较哈希感兴趣,则效率会稍低。)

如果需要将哈希表示为字符串,可以使用
位转换器将其转换为十六进制:

static string CalculateMD5(string filename)
{
    using (var md5 = MD5.Create())
    {
        using (var stream = File.OpenRead(filename))
        {
            var hash = md5.ComputeHash(stream);
            return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
        }
    }
}

这是我发现的一个稍微简单的版本。它一次读取整个文件,只需要使用一个指令

byte[] ComputeHash(string filePath)
{
    using (var md5 = MD5.Create())
    {
        return md5.ComputeHash(File.ReadAllBytes(filePath));
    }
}
我就是这样做的:

using System.IO;
using System.Security.Cryptography;

public string checkMD5(string filename)
{
    using (var md5 = MD5.Create())
    {
        using (var stream = File.OpenRead(filename))
        {
            return Encoding.Default.GetString(md5.ComputeHash(stream));
        }
    }
}

我知道这个问题已经得到了回答,但我用的是:

using (FileStream fStream = File.OpenRead(filename)) {
    return GetHash<MD5>(fStream)
}
使用(FileStream fStream=File.OpenRead(filename)){
返回GetHash(fStream)
}
其中GetHash

public static String GetHash<T>(Stream stream) where T : HashAlgorithm {
    StringBuilder sb = new StringBuilder();

    MethodInfo create = typeof(T).GetMethod("Create", new Type[] {});
    using (T crypt = (T) create.Invoke(null, null)) {
        byte[] hashBytes = crypt.ComputeHash(stream);
        foreach (byte bt in hashBytes) {
            sb.Append(bt.ToString("x2"));
        }
    }
    return sb.ToString();
}

公共静态字符串GetHash(Stream-Stream),其中T:HashAlgorithm{
StringBuilder sb=新的StringBuilder();
MethodInfo create=typeof(T).GetMethod(“create”,新类型[]{});
使用(T crypt=(T)create.Invoke(null,null)){
byte[]hashBytes=crypt.ComputeHash(流);
foreach(字节bt,以hashBytes表示){
某人附加(bt.ToString(“x2”));
}
}
使某人返回字符串();
}

可能不是最好的方法,但它很方便。

如果您需要计算MD5以查看它是否与Azure blob的MD5匹配,那么这个问题和答案可能会有所帮助:

我知道我参加聚会迟到了,但在实际实施解决方案之前执行了测试

我对内置的MD5类进行了测试。在我的例子中,内置类花费了13秒,其中md5sum.exe在每次运行中也花费了16-18秒

    DateTime current = DateTime.Now;
    string file = @"C:\text.iso";//It's 2.5 Gb file
    string output;
    using (var md5 = MD5.Create())
    {
        using (var stream = File.OpenRead(file))
        {
            byte[] checksum = md5.ComputeHash(stream);
            output = BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower();
            Console.WriteLine("Total seconds : " + (DateTime.Now - current).TotalSeconds.ToString() + " " + output);
        }
    }

用于动态生成的PDF。 创建日期和修改日期将始终不同

您必须删除它们或将它们设置为常量值

然后生成md5散列以比较散列


您可以使用
PDFStamper
删除或更新日期。

如果您想要看起来“标准”的md5,可以执行以下操作:返回
BitConverter.ToString(md5.ComputeHash(stream)).Replace(“-”,“”)。ToLower()
MD5位于System.Security.Cryptography中-只是为了进一步公开信息。@KalaJ:如果您试图发现故意篡改,那么CRC32是完全不合适的。如果您只是在谈论如何发现数据传输失败,那没关系。就我个人而言,我可能只是出于习惯而使用SHA-256:)我不知道在.NET中是否支持CRC32,但您可能可以尽快搜索:)@aquinas我认为
.Replace(“-”,String.Empty)
是更好的方法。我进行了一个小时的调试,因为我在将用户输入与文件哈希进行比较时得到了错误的结果。@wuethrich44,我认为您遇到的问题是,如果您在aquinas注释中逐字复制/粘贴代码;我碰巧注意到了同样的事情。原始HTML中的“空”引号之间有两个不可见字符——“零宽度非连接符”和Unicode“零宽度空格”。我不知道它是否在原始注释中,或者是否应该归咎于此。使用
ReadAllBytes
的缺点是它将整个文件加载到单个数组中。这对于大于2 GiB的文件根本不起作用,甚至对于中等大小的文件也会给GC带来很大压力。乔恩的答案只是稍微复杂一点,但并不存在这些问题。所以我更喜欢他的答案,而不是你的答案。在不使用第一个大括号的情况下,依次输入
using
s
using(var md5=md5.Create())using(var stream=File.OpenRead(filename))
让你每行使用一次,而不需要进行不必要的缩进。@NiKiZe你可以将整个程序放在一行上,并消除所有缩进。您甚至可以使用XYZ作为变量名!对其他人有什么好处?@DerekJohnson我想说的一点可能是“并且只需要使用一个
指令”
并不是将所有内容读入内存的好理由。更有效的方法是将数据流式传输到
ComputeHash
,如果可能的话,只能使用
使用
,但我完全理解您是否希望避免额外的缩进。我投票给了您,因为更多的人需要这样做。我认为使用
块交换
会很有用,因为打开文件很可能会失败。早期失败/快速方法为您节省了在这种情况下创建(和销毁)MD5实例所需的资源。您还可以使用
省略第一个
的大括号,并在不丢失可读性的情况下保存缩进级别。这会将16字节长的结果转换为16个字符的字符串,而不是预期的32个字符的十六进制值。此代码不会产生预期结果(假定预期)。同意@NiKiZe@Palec,您是否意识到您刚刚优化了失败案例?“当我们的程序出错时,它会比以前更快地向用户返回该错误。0000000000001!”。除非它的盒子处理大量的请求,像这样的SMT可能很重要,否则它是一个非常非常低值的优化。我已经将它转换为一个扩展方法,并删除了反射代码。
publicstaticstringgethash(这个流),其中T:HashAl
    DateTime current = DateTime.Now;
    string file = @"C:\text.iso";//It's 2.5 Gb file
    string output;
    using (var md5 = MD5.Create())
    {
        using (var stream = File.OpenRead(file))
        {
            byte[] checksum = md5.ComputeHash(stream);
            output = BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower();
            Console.WriteLine("Total seconds : " + (DateTime.Now - current).TotalSeconds.ToString() + " " + output);
        }
    }