2012-06-20 20 views
8

मेरे पास inputStream है जो मैं हैश की गणना करने और फ़ाइल को डिस्क पर सहेजने के लिए उपयोग करना चाहता हूं। मैं जानना चाहता हूं कि कुशलता से यह कैसे करें। क्या मुझे समवर्ती रूप से ऐसा करने के लिए कुछ कार्य का उपयोग करना चाहिए, क्या मुझे स्ट्रीम स्ट्रीम को दो धाराओं में डुप्लिकेट करना चाहिए, एक saveFile विधि के लिए और computeHash विधि के लिए, या मुझे कुछ और करना चाहिए?फ़ाइल सहेजते समय कंप्यूटिंग हैश?

+1

मैं हाल ही में एक ऐसी ही प्रश्न पूछा: http://stackoverflow.com/questions/10985282/generate-running-hash-or-checksum-in-c (उत्तर दिए गए हैं संभावित रूप से बाधाओं के कारण लागू), मैंने मान लिया है कि "हैश" का मतलब एमडी 5, एसएएक्स, आदि –

+0

है मैंने SHA256Cng का उपयोग किया है और फ़ाइल को भी सहेज सकता है।मेरा प्रश्न दोनों एक ही समय में (कार्यों/वायदा का उपयोग करके) या अनुक्रमिक रूप से (एक फाइलस्ट्रीम पढ़ने से आंतरिक सूचक को स्थानांतरित करने के बारे में अधिक है, इसलिए मैं पॉइंटर को शून्य पर रीसेट कर सकता हूं या पॉइंटर डुप्लिकेट कर सकता हूं)। मुझे नहीं पता कि कौन सा बेहतर है और इसे कैसे करें। – Dave

+4

* लिंक किए गए प्रश्न को पढ़ने के बारे में संगीत * (एक "स्ट्रीम स्प्लिटर" पर भी विचार करें, जिसका उपयोग दो आउटपुट धाराओं के बीच प्रतिलिपि बनाने के कुछ मैन्युअल काम को कम करने के लिए किया जा सकता है।) –

उत्तर

0

आपको हैश करने के लिए आपको byte[] में धारा के बाइट्स को भरना होगा।

+1

आप भी एक स्ट्रीम पास कर सकते हैं। धारा को बाइट [] में परिवर्तित करने के क्या फायदे होंगे? – Dave

+0

मैं, किसी कारण से, उस अधिभार को नहीं देखा। कभी। मैं तपस्या में 10 "हेल बिल गेट्स" कहूंगा। – bluevector

+1

@ डेव कोई फायदा नहीं है। 'बाइट []' और 'स्ट्रीम' लेने वाले दोनों फॉर्म अवरुद्ध हो रहे हैं और पूरे डेटा को एक-शॉट में उम्मीद कर रहे हैं। धागे और एक विशेष 'स्ट्रीम' के साथ ... लेकिन यह सिर्फ और अधिक समस्याएं जोड़ता है तो यह हल हो जाता है ... –

3

ब्लॉक स्तर पर संचालित हैश एल्गोरिदम का उपयोग करने के बारे में क्या? आप ब्लॉक को हैश (ट्रांसफॉर्मब्लॉक का उपयोग करके) में जोड़ सकते हैं और बाद में ब्लॉक में फ़ाइल फ़ोरैच ब्लॉक में ब्लॉक लिख सकते हैं।

untested है किसी न किसी शॉट:

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

मैं मैन्युअल ब्लॉक प्रोसेसिंग का बड़ा प्रशंसक नहीं हूं, लेकिन यह काम करना चाहिए। (मुझे लगता है कि क्रिप्टोस्ट्रीम एक आसान दृष्टिकोण है जो एक सुंदर रैपर होने के लिए नीचे आता है।) –

+0

सहमत हैं। मैं आम तौर पर उन्हें प्लेग की तरह से बचता हूं (हालिया स्ट्रीम.कोपीटो विधि के लिए भगवान का शुक्र है) ... मुझे लगता है कि समस्या को हल करने का यह सबसे अच्छा तरीका है। इसके अलावा, एक दूसरा पठन मुझे लगता है कि मेरे पास एक बग है जहां अंतिम ब्लॉक दो बार धोया गया है ... सटीक एमडी 5 होने के लिए, आपको ईओएस का पता लगाना होगा और अंतिम ब्लॉक को अलग-अलग संभालना होगा। –

1

यह सबसे अच्छा विकल्प नहीं हो सकता है, लेकिन मैं Stream वंशज/आवरण के लिए जाने के लिए चुनते हैं, एक है कि एक वास्तव में करने के लिए फ़ाइल लिखने के लिए पास-थ्रू किया जाएगा डिस्क

तो:

  • निकाले जाते हैं 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(); 
0

यहाँ मेरी हल है, यह एक एक csv फ़ाइल के रूप में structs की सरणी (टिक चर) (CsvHelper nuget पैकेज का उपयोग) लिखते हैं और फिर प्रत्यय का उपयोग कर चेकसम प्रयोजनों के लिए एक हैश पैदा करता है। sha256

मैं इसे स्मृति स्ट्रीम में सीएसवी लिखकर करता हूं, फिर डिस्क पर मेमोरी स्ट्रीम लिखता हूं, फिर हैश अलगो में मेमोरीस्ट्रीम पास करता हूं।

यह समाधान पूरी फ़ाइल को मेमोरीस्ट्रीम के रूप में रख रहा है। बहु-गीगाबाइट फ़ाइलों को छोड़कर सब कुछ ठीक है जो आपको राम से बाहर चलाएगा। अगर मुझे इसे फिर से करना पड़ा, तो शायद मैं क्रिप्टोस्ट्रीम दृष्टिकोण का उपयोग करने की कोशिश करता हूं, लेकिन यह मेरे पूर्ववर्ती उद्देश्यों के लिए पर्याप्त है।

मैंने एक तृतीय पक्ष टूल के माध्यम से सत्यापित किया है कि हैश वैध हैं।

//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

संबंधित मुद्दे