2012-06-20 15 views
8

ハッシュを計算してディスクに保存するために使用したいinputStreamがあります。私はそれを効率的に行う方法を知りたいです。ストリームパスを2つのストリーム、1つはsaveFileメソッド、もう1つはcomputeHashメソッドのために複製する必要がありますか、それとも何か別の作業を行う必要がありますか?ファイルを保存している間にハッシュを計算していますか?

+1

を参照してください私は最近、同様の質問を:http://stackoverflow.com/questions/10985282/generate-running-hash-or-checksum-in-cを(答えがありますおそらく制約のために適用される可能性があります)、私はMD5、SHAxなどを意味する "ハッシュ"と仮定しました。 –

+0

私はSHA256Cngを使用しましたが、ファイルも保存できます。私の質問は、(タスク/先物を使用して)同時に(タスクを使用して)または順次(ファイルストリームを読むと内部ポインタを移動するので、ポインタをゼロにリセットするか、ポインタを複製すること)の両方に関することです。私はどちらが良いか、それを行う方法がわかりません。 – Dave

+4

*リンクされた質問を読むことに夢中になる*(ストリームストリームスプリッタを考えてみると、2つの出力ストリーム間の手動コピー作業を潜在的に減らすことができます) –

答えて

0

あなたはそれらをハッシュするためにbyte[]にストリームのバイトを詰め込むする必要があります。

+1

ストリームも渡すことができます。ストリームをbyte []に​​変換するとどんなメリットがありますか? – Dave

+0

私は何らかの理由で、その過負荷を見ていませんでした。これまで私は苦行して10 "雹紙幣ゲイツ"と言うだろう。 – bluevector

+1

@Dave利点はありません。 'byte []'と 'Stream'を取る形式は両方ともブロックしており、データ全体をワンショットで期待しています。スレッドと特殊な 'Stream'を使用していますが、それはもっと問題を追加します。 –

3

ブロックレベルで動作するハッシュアルゴリズムを使用するとどうなりますか?ブロックをハッシュに追加し(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; 
} 
+0

私は手動ブロック処理の大きなファンではありませんが、これはうまくいくはずです。 (私は、CryptoStreamはかなりラッパーであるという単純なアプローチだと思う) –

+0

同意。私は一般的に疫病のようにそれらを避ける(最近のStream.CopyToメソッドの神に感謝)...私はこれが問題を解決する最善の方法だと思う。また、2回目の読み込みでは、最終ブロックが2回ハッシュされたバグがあると思います...正確なMD5であるためには、EOSを検出して最後のブロックを別に処理する必要があります。 –

1

はそれが最良の選択肢ではないかもしれませんが、私はStream子孫/ラッパーのために行くことを選ぶだろう、パススルーされるだろう1、実際にファイルを書き込むため1ディスク。だから、

  • Stream
  • から派生のブロックをハッシュWrite()Write()と関連するすべてのもの
  • を実装
  • を書くために、ターゲット・ストリームとなるようStream _inner;などつのメンバーを持っていますデータと呼ん_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(); 
0

が私の解決策ですが、それは(CsvHelper nugetパッケージを使用して)CSVファイルとして構造体の配列(ティック変数)を書き込み、その後、接尾辞を使用して、チェックサムの目的のためにハッシュを作成します。 SHA256

私はハッシュアルゴへのMemoryStreamを渡し、その後、その後、ディスクにメモリストリームを書き込み、MemoryStreamをへのcsvファイルを書き込むことによってこれを行います。

この解決策は、ファイル全体をメモリストリームとして保持しています。ラムからあなたを追い出すマルチギガバイトのファイルを除いて、すべてのことがうまくいきます。これをやり直さなければならないとすれば、私はおそらくCryptoStreamのアプローチを試してみるだろうが、これは私の予見可能な目的のためには十分だ。

私はサードパーティのツールを介してハッシュが有効であることを確認しました。ここで

は、コードは次のとおりです。

//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<TickDataClassMap>(); 
         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()); 
          } 
         } 

        } 

       } 
      } 
2

この方法は、コピーして、連鎖ストリームにハッシュされます。

private static byte[] CopyAndHash(string source, string target, Action<double> progress, Func<bool> 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