2009-12-08 8 views
45

मैं एक फ़ाइल के SHA-1 मान की गणना करने की कोशिश कर रहा हूं।पाइथन ने "हैशिब.शा 1" को फ़ाइल के लिए "गिट हैश-ऑब्जेक्ट" से अलग क्यों किया है?

मैं इस स्क्रिप्ट गढ़े गए हैं: मैं इस हैश मान प्राप्त एक विशिष्ट फ़ाइल के लिए

def hashfile(filepath): 
    sha1 = hashlib.sha1() 
    f = open(filepath, 'rb') 
    try: 
     sha1.update(f.read()) 
    finally: 
     f.close() 
    return sha1.hexdigest() 

:
8c3e109ff260f7b11087974ef7bcdbdc69a0a3b9
लेकिन जब मैं Git hash_object साथ मूल्य की गणना, तो मैं यह मान मिलता है: d339346ca154f6ed9e92205c3c5c38112e761eb7

वे अलग कैसे होते हैं? क्या मैं कुछ गलत कर रहा हूं, या क्या मैं सिर्फ अंतर को अनदेखा कर सकता हूं?

+2

यदि आप हैंश का उपयोग करने की योजना बना रहे हैं तो आप वास्तव में अंतर को अनदेखा नहीं कर सकते हैं। –

+0

उल्लेख करने के लिए भूल गए, सिर्फ एक संदर्भ के रूप में इस्तेमाल किया गया गिट, उन्हें एक साथ उपयोग करने के लिए नहीं जा रहा है। – Ikke

+1

यदि फ़ाइल काफी बड़ी हो सकती है, तो आप इसे एक समय में एक ब्लॉक संसाधित कर सकते हैं ताकि आपको रैम में पूरी चीज की आवश्यकता न हो: http://stackoverflow.com/questions/7829499/using-hashlib-to- compute-md5-digest-of-a-file-in-python3 – rakslice

उत्तर

51

Git इस तरह हैश गणना करता है:

def sha1OfFile(filepath): 
    import hashlib 
    with open(filepath, 'rb') as f: 
     return hashlib.sha1(f.read()).hexdigest() 

दूसरी सोचा पर::

sha1("blob " + filesize + "\0" + data) 

Reference

+0

मुझे इसे देखना चाहिए था, धन्यवाद। – Ikke

+0

कोई जांच नहीं, संदर्भित लिंक काफी अलग है, बस इसे भाग्य से ढूंढने के लिए हुआ। –

+13

यह उल्लेख किया जाना चाहिए कि गिट यह लंबाई विस्तार हमलों से बचने के लिए करता है। – Omnifarious

31

संदर्भ के लिए, अधिक संक्षिप्त संस्करण है, हालांकि मैं यह कभी नहीं देखा है, मुझे लगता है कि f.read() पूर्ण फ़ाइल से कम लौटने के लिए, या कई-गीगाबाइट फ़ाइल के लिए, स्मृति से बाहर चलाने के लिए f.read() के लिए संभावित है। ,

def sha1OfFile(filepath): 
    import hashlib 
    sha = hashlib.sha1() 
    with open(filepath, 'rb') as f: 
     for line in f: 
      sha.update(line) 
     return sha.hexdigest() 

हालांकि कोई गारंटी नहीं कि '\n' बिल्कुल फ़ाइल दिखाए जाते हैं इसलिए इस तथ्य है कि for पाश हमें ब्लॉक दे देंगे नहीं है: हर किसी की उन्नति के लिए, हम मानते हैं कि ठीक करने के लिए कैसे करते हैं: कि करने के लिए एक पहले ठीक है '\n' में समाप्त होने वाली फ़ाइल में से हमें वही समस्या मिल सकती है जो हमने मूल रूप से की थी।

def sha1OfFile(filepath): 
    import hashlib 
    sha = hashlib.sha1() 
    with open(filepath, 'rb') as f: 
     while True: 
      block = f.read(2**10) # Magic number: one-megabyte blocks. 
      if not block: break 
      sha.update(block) 
     return sha.hexdigest() 
: दुर्भाग्य से, मैं संभव के रूप में बड़ी फ़ाइल के ब्लॉक से अधिक पुनरावृति करने के लिए है, जो मुझे लगता है कि इसका मतलब है कि हम एक while True: ... break पाश के साथ और ब्लॉक आकार के लिए एक जादुई संख्या के साथ फंस रहे हैं किसी भी इसी तरह pythonic तरीका नहीं दिख रहा है

बेशक, कौन कहता है कि हम एक मेगाबाइट तारों को स्टोर कर सकते हैं। हम शायद कर सकते हैं, लेकिन क्या होगा यदि हम एक छोटे से एम्बेडेड कंप्यूटर पर हैं?

मेरी इच्छा है कि मैं एक क्लीनर तरीके के बारे में सोच सकूं जो कि बड़ी फाइलों पर स्मृति से बाहर नहीं होने की गारंटी है और इसमें जादू संख्याएं नहीं हैं और साथ ही साथ मूल सरल पायथनिक समाधान भी किया जाता है।

+0

दूसरे विचार पर, इसमें समस्या हो सकती है अगर f.read() पूरी फ़ाइल को वापस नहीं कर सकता (उदा।, बहु-गीगाबाइट फ़ाइलों के मामले में) और इसलिए इसे शायद हिस्सों पर फिर से चालू करना चाहिए। – Ben

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