2010-01-23 12 views
31

मैं काफी बड़ी फ़ाइलों (गीगाबाइट) की चेकसम गणना करनी है। यह निम्नलिखित विधि का उपयोग कर पूरा किया जा सकता:buffered पढ़ने के साथ MD5 (या अन्य) हैश की गणना करना संभव है?

private byte[] calcHash(string file) 
    { 
     System.Security.Cryptography.HashAlgorithm ha = System.Security.Cryptography.MD5.Create(); 
     FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read); 
     byte[] hash = ha.ComputeHash(fs); 
     fs.Close(); 
     return hash; 
    } 

हालांकि, फ़ाइलों सामान्य रूप से एक बफ़र ढंग से बस पहले से लिखे गए हैं (जैसे लेखन 32MB की एक समय में)। मैं इतना विश्वास है कि मैं एक हैश समारोह है कि मुझे लेखन के रूप में एक ही समय में एक MD5 (या अन्य) हैश की गणना करने की अनुमति दी है, जिसकी ओवरराइड देखा हूँ, अर्थात्: एक बफर के हैश की गणना, तो खिला अगले चरण में हैश जिसके परिणामस्वरूप कि ।

कुछ इस तरह: (स्यूडोकोड-ish)

byte [] hash = new byte [] { 0,0,0,0,0,0,0,0 }; 
while(!eof) 
{ 
    buffer = readFromSourceFile(); 
    writefile(buffer); 
    hash = calchash(buffer, hash); 
} 

हैश अब क्या पूरी फ़ाइल पर calcHash समारोह चलाकर पूरा किया जाएगा करने के लिए sililar है।

अब, मैं उस तरह अधिलेखन the.Net 3.5 फ्रेमवर्क में नहीं मिल सकता है, मैं सपना देख रहा हूँ? क्या यह कभी अस्तित्व में नहीं है, या क्या मैं खोज में बस लूसी हूं? एक बार में लेखन और चेकसम गणना दोनों करने का कारण यह है कि बड़ी फ़ाइलों के कारण यह समझ में आता है।

उत्तर

45

आप TransformBlock और TransformFinalBlock भागों में डेटा को संसाधित करने के तरीकों का उपयोग करते हैं।

// Init 
MD5 md5 = MD5.Create(); 
int offset = 0; 

// For each block: 
offset += md5.TransformBlock(block, 0, block.Length, block, 0); 

// For last block: 
md5.TransformFinalBlock(block, 0, block.Length); 

// Get the has code 
byte[] hash = md5.Hash; 

ध्यान दें: यह (कम से कम MD5 प्रदाता के साथ) काम करता है TransformBlock लिए सभी ब्लॉक भेजने और फिर प्रक्रिया को अंतिम रूप देने के लिए TransformFinalBlock एक खाली ब्लॉक भेजने के लिए।

+1

ओएमजी, उसी प्रारूपण का उपयोग करके, एक ही सुझाव पोस्ट किया गया है =) –

+0

ठीक है, लेकिन एक संदर्भ भी प्रदान करने के लिए +1! –

+1

Ay caramba! वो रहा! वह वह काम था जिसे मैं खोज रहा था। जानना अच्छा है कि मैं इसे सब कुछ नहीं बना रहा था। तुरंत उत्तर देने के लिए गुफा और रूबेन्स के लिए धन्यवाद। आप दोनों को +1, मैं शामिल कोड उदाहरण के कारण इस जवाब को स्वीकार करूंगा। –

3

हैश एल्गोरिदम इस स्थिति को संभालने के लिए उम्मीद कर रहे हैं और आमतौर पर 3 कार्यों के साथ लागू किया जाता है:

hash_init() - संसाधनों के आवंटन और हैश शुरू करने के लिए कहा जाता है।
hash_update() - के रूप में यह आता है नए डेटा से कहा जाता है।
hash_final() - गणना और मुक्त संसाधनों को पूरा करें।

http://www.openssl.org/docs/crypto/md5.html या सी में अच्छा, मानक उदाहरण के लिए http://www.openssl.org/docs/crypto/sha.html पर देखो; मुझे यकीन है कि आपके मंच के लिए समान पुस्तकालय हैं।

+0

अच्छा जवाब, लेकिन "यह नेट में कहां है?" प्रश्न का हिस्सा खुला रहता है। –

+0

@ पास्कल: नीचे दिए गए 2 अच्छे उत्तरों को देखें, जिनमें से दोनों को आपकी टिप्पणी से पहले पोस्ट किया गया था। –

4

लगता है के रूप में इस नमूने में बताया गया आप TransformBlock/TransformFinalBlock उपयोग करने के लिए कर सकते हैं,: Displaying progress updates when hashing large files

+0

वह लिंक मर चुका है, इसके बजाय इसे आजमाएं: http://www.infinitec.de/post/2007/06/09/ डिस्प्लेइंग- प्रोग्रेस- अपडेट्स- जब- hashing-large-files.aspx – Cumbayah

48

मैं, ऊपर, लेकिन पूर्णता के लिए के लिए जवाब है, और किया जा रहा है एक अधिक सामान्य समाधान चाहते CryptoStream वर्ग को देखें। आप पहले से ही धाराओं संभाल रहे हैं, तो यह एक CryptoStream में अपनी स्ट्रीम रैप करने के लिए आसान है, एक HashAlgorithmICryptoTransform पैरामीटर के रूप में पारित करने।

var file = new FileStream("foo.txt", FileMode.Open, FileAccess.Write); 
var md5 = MD5.Create(); 
var cs = new CryptoStream(file, md5, CryptoStreamMode.Write); 
while (notDoneYet) 
{ 
    buffer = Get32MB(); 
    cs.Write(buffer, 0, buffer.Length); 
} 
System.Console.WriteLine(BitConverter.ToString(md5.Hash)); 

आप हैश (ताकि HashAlgorithm जानता है कि यह किया है) से पहले धारा बंद करने के लिए हो सकता है।

0

मुझे बस कुछ ऐसा करना पड़ा है, लेकिन फ़ाइल को असीमित रूप से पढ़ना चाहता था। यह ट्रांसफॉर्मब्लॉक और ट्रांसफॉर्मफिनब्लॉक का उपयोग कर रहा है और मुझे Azure के साथ संगत उत्तर दे रहा है, इसलिए मुझे लगता है कि यह सही है!

private static async Task<string> CalculateMD5Async(string fullFileName) 
{ 
    var block = ArrayPool<byte>.Shared.Rent(8192); 
    try 
    { 
    using (var md5 = MD5.Create()) 
    { 
     using (var stream = new FileStream(fullFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 8192, true)) 
     { 
      int length; 
      while ((length = await stream.ReadAsync(block, 0, block.Length).ConfigureAwait(false)) > 0) 
      { 
       md5.TransformBlock(block, 0, length, null, 0); 
      } 
      md5.TransformFinalBlock(block, 0, 0); 
     } 
     var hash = md5.Hash; 
     return Convert.ToBase64String(hash); 
     } 
    } 
    finally 
    { 
     ArrayPool<byte>.Shared.Return(block); 
    } 
} 
+0

'अरेपूल' क्या है? – Shimmy

+0

ठीक है: ['ArrayPool'] (https://github.com/dotnet/corefx/blob/master/src/System.Buffers/src/System/Buffers/ArrayPool.cs), पैकेज को स्थापित करने की आवश्यकता है [' System.Buffers'] (https://preview.nuget.org/packages/System.Buffers)। – Shimmy