2

我需要计算许多大文件的 MD5 校验和。代码非常简单:

System.IO.FileStream file = new System.IO.FileStream(strFullPath, FileMode.Open);
fsFile.Seek(1000, SeekOrigin.Begin);    //skip some chars if need be
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] arrBtMd5 = md5.ComputeHash(fsFile);

如果我想执行以下操作之一,问题就开始了:

  • 计算同一个文件的多个哈希函数(md5、sha1、crc32 和-what-not)。
  • 计算整个文件的 MD5 和跳过某些标题行的同一文件的另一个 MD5。

如果我一个一个地这样做,同一个文件将被读取多次。磁盘 I/O 是系统的瓶颈,所以我的问题是:

  1. .NET 编译器/框架可以识别我多次读取同一个文件并优化操作吗?(我很确定它会做一些事情,因为当我添加第二个没有标题的 md5 计算时,影响不是很大)。
  2. 我可以使用什么技术在多个“消费者”之间共享相同的 FileStream?我想用 FileStream 只浏览一次文件,然后拆分数据以供并行工作的散列函数使用。
4

2 回答 2

2

我同意 Henk Holterman 的回应。您必须自己进行拆分。但是,您可以做的是不使用单个 ComputeHash 调用来计算完整的哈希,而是通过TransformBlock调用以字节块的形式进行计算。有关示例,请参见此处

有了这个,您可以自己实例化一个大小的缓冲区,并将其作为参数提供给随后的并行 TransformBlock 调用。

编辑:这是一些完成工作的代码

        static void Hash2Md5inParallel()
    {
        string strFullPath = YourFilePathGoesHere;
        byte[] Buffer = new Byte[1000]; //Instantiate Buffer to copy bytes.
        byte[] DumpBuffer = new Byte[1000];  //Send output to bin.

        System.Security.Cryptography.MD5 md5_1 = new System.Security.Cryptography.MD5CryptoServiceProvider();
        System.Security.Cryptography.MD5 md5_2 = new System.Security.Cryptography.MD5CryptoServiceProvider();


        System.IO.FileStream file = new System.IO.FileStream(strFullPath, FileMode.Open);
        file.Seek(1000, SeekOrigin.Begin);    //skip some chars if need be

        int BytesToHash = 0;
        do
        {

            BytesToHash = file.Read(Buffer, 0, 1000);


            md5_1.TransformBlock(Buffer, 0, BytesToHash, DumpBuffer, 0);

            //enter some code to skip some bytes for the other hash if you like...
            md5_2.TransformBlock(Buffer, 0, BytesToHash, DumpBuffer, 0);
        }
        while (BytesToHash > 0); //Repeat until no more bytes.

        //call TransformFinalBlock to finish hashing - empty block is enough
        md5_1.TransformFinalBlock(new byte[0], 0, 0);
        md5_2.TransformFinalBlock(new byte[0], 0, 0);

        //Get both Hashs.
        byte[] hash1 = md5_1.Hash;
        byte[] hash2 = md5_2.Hash;


    }
于 2013-07-22T11:09:27.957 回答
1

1 .NET 编译器/框架可以识别我多次读取同一个文件并优化操作吗?(我很确定它会做一些事情,因为当我添加第二个没有标题的 md5 计算时,影响不是很大)。

不会,但底层操作系统 (Windows) 会缓存和缓冲您的文件。

2 我可以使用什么技术在多个“消费者”之间共享相同的 FileStream?我想用 FileStream 只浏览一次文件,然后拆分数据以供并行工作的散列函数使用。

Afaik 没有可用的“streamsplitters”,但您可以将其读入 MemoryStream 并重用它。但这仅适用于相当小的文件。

我会把它留给 Windows,不做任何特别的事情。

您可以尝试并行运行哈希器,这是一种罕见的情况,其中一个磁盘上的并行 I/O 可能会工作。

于 2013-07-22T09:57:22.947 回答