保存文件时计算哈希值?

我有一个inputStream ,我想用它来计算哈希并将文件保存到磁盘。 我想知道如何有效地做到这一点。 我是否应该使用某些任务同时执行此操作,是否应将流传递复制到两个流,一个用于saveFile方法,另一个用于computeHash方法,或者我应该执行其他操作?

使用在块级别上运行的哈希算法怎么样? 您可以将块添加到哈希(使用TransformBlock),然后将块写入流中的foreach块文件。

未经测试的粗糙镜头:

 using System.IO; using System.Security.Cryptography; ... public byte[] HashedFileWrite(string filename, Stream input) { var hash_algorithm = MD5.Create(); using(var file = File.OpenWrite(filename)) { byte[] buffer = new byte[4096]; int read = 0; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { hash_algorithm.TransformBlock(buffer, 0, read, null, 0); file.Write(buffer, 0, read); } hash_algorithm.TransformFinalBlock(buffer, 0, read); } return hash_algorithm.Hash; } 

此方法将使用链接流复制和散列。

 private static byte[] CopyAndHash(string source, string target, Action progress, Func isCanceled) { using(var sha512 = SHA512.Create()) using (var targetStream = File.OpenWrite(target)) using (var cryptoStream = new CryptoStream(targetStream, sha512, CryptoStreamMode.Write)) using (var sourceStream = File.OpenRead(source)) { byte[] buffer = new byte[81920]; int read; while ((read = sourceStream.Read(buffer, 0, buffer.Length)) > 0 && !isCanceled()) { cryptoStream.Write(buffer, 0, read); progress?.Invoke((double) sourceStream.Length / sourceStream.Position * 100); } File.SetAttributes(target, File.GetAttributes(source)); return sha512.Hash; } } 

完整示例请参阅https://gist.github.com/dhcgn/da1637277d9456db9523a96a0a34da78

它可能不是最好的选择,但我会选择使用Stream descendant / wrapper,这是一个实际将文件写入磁盘的传递。

所以:

  • 源自Stream
  • 有一个成员,如Stream _inner; 这将是要写入的目标流
  • 实现Write()和所有相关的东西
  • Write()散列数据块并调用_inner.Write()

用法示例

 Stream s = File.Open("infile.dat"); Stream out = File.Create("outfile.dat"); HashWrapStream hasher = new HashWrapStream(out); byte[] buffer=new byte[1024]; int read = 0; while ((read=s.Read(buffer)!=0) { hasher.Write(buffer); } long hash=hasher.GetComputedHash(); // get actual hash hasher.Dispose(); s.Dispose(); 

您需要将流的字节填充到byte[]中以便对它们进行哈希处理。

这是我的解决方案,它将一个结构数组(ticks变量)写为csv文件(使用CsvHelper nuget包),然后使用后缀.sha256为校验和目的创建一个哈希值。

我这样做是通过将csv写入memoryStream,然后将内存流写入磁盘,然后将内存流传递给哈希算法。

此解决方案将整个文件保留为内存流。 除了可以让你从ram中运行的多GB文件之外的一切都很好。 如果我不得不再次这样做,我可能会尝试使用CryptoStream方法,但这对于我可预见的目的来说已经足够了。

我已通过第三方工具validation哈希值是否有效。

这是代码:

 //var ticks = **some_array_you_want_to_write_as_csv** using (var memoryStream = new System.IO.MemoryStream()) { using (var textWriter = new System.IO.StreamWriter(memoryStream)) { using (var csv = new CsvHelper.CsvWriter(textWriter)) { csv.Configuration.DetectColumnCountChanges = true; //error checking csv.Configuration.RegisterClassMap(); csv.WriteRecords(ticks); textWriter.Flush(); //write to disk using (var fileStream = new System.IO.FileStream(targetFileName, System.IO.FileMode.Create)) { memoryStream.Position = 0; memoryStream.CopyTo(fileStream); } //write sha256 hash, ensuring that the file was properly written using (var sha256 = System.Security.Cryptography.SHA256.Create()) { memoryStream.Position = 0; var hash = sha256.ComputeHash(memoryStream); using (var reader = System.IO.File.OpenRead(targetFileName)) { System.IO.File.WriteAllText(targetFileName + ".sha256", hash.ConvertByteArrayToHexString()); } } } } }