python फ़ाइल के एमडी 5 चेकसम उत्पन्न करना




md5 checksum (3)

क्या Python में फ़ाइलों की सूची के MD5 चेकसम उत्पन्न करने (और जांचने) का कोई आसान तरीका है? (मेरे पास एक छोटा सा प्रोग्राम है जिस पर मैं काम कर रहा हूं, और मैं फ़ाइलों के चेकसम की पुष्टि करना चाहता हूं)।


आप hashlib.md5() उपयोग कर सकते हैं

ध्यान दें कि कभी-कभी आप पूरी फ़ाइल को स्मृति में फिट नहीं कर पाएंगे। उस स्थिति में, आपको अनुक्रमिक रूप से 4096 बाइट्स के हिस्सों को पढ़ना होगा और उन्हें एमडी 5 फ़ंक्शन पर फ़ीड करना होगा:

def md5(fname):
    hash_md5 = hashlib.md5()
    with open(fname, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

एक तरीका है कि सुंदर स्मृति अक्षम है

एक दस्तावेज:

import hashlib
def file_as_bytes(file):
    with file:
        return file.read()

print hashlib.md5(file_as_bytes(open(full_path, 'rb'))).hexdigest()

फाइलों की सूची:

[(fname, hashlib.md5(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]

लेकिन, एमडी 5 टूटा हुआ है और (आईएमएचओ) डरावनी बहिष्करण चेतावनियों के साथ आना चाहिए और लाइब्रेरी से हटा दिया जाना चाहिए, तो यहां वास्तव में आपको यह कैसे करना चाहिए:

[(fname, hashlib.sha256(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]

यदि आप केवल 128 बिट्स पाचन के लायक चाहते हैं तो आप कर सकते हैं .digest()[:16]

यह आपको टुपल्स की एक सूची देगा, प्रत्येक टुपल जिसमें उसकी फ़ाइल का नाम और उसका हैश होगा।

फिर मैं दृढ़ता से एमडी 5 के उपयोग पर सवाल उठाता हूं। आपको कम से कम SHA1 का उपयोग करना चाहिए। कुछ लोग सोचते हैं कि जब तक आप 'क्रिप्टोग्राफिक' उद्देश्यों के लिए MD5 का उपयोग नहीं कर रहे हैं, तो आप ठीक हैं। लेकिन सामान की शुरूआत की तुलना में दायरे में व्यापक होने की प्रवृत्ति होती है, और आपका आकस्मिक भेद्यता विश्लेषण पूरी तरह से त्रुटिपूर्ण साबित हो सकता है। गेट के बाहर सही एल्गोरिदम का उपयोग करने की आदत में होना सबसे अच्छा है। यह सिर्फ अक्षरों का एक अलग समूह टाइप कर रहा है। यह इतना मुश्किल नही है।

यहां एक तरीका है जो अधिक जटिल है, लेकिन स्मृति कुशल है :

import hashlib

def hash_bytestr_iter(bytesiter, hasher, ashexstr=False):
    for block in bytesiter:
        hasher.update(block)
    return (hasher.hexdigest() if ashexstr else hasher.digest())

def file_as_blockiter(afile, blocksize=65536):
    with afile:
        block = afile.read(blocksize)
        while len(block) > 0:
            yield block
            block = afile.read(blocksize)


[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.md5()))
    for fname in fnamelst]

और, फिर से, चूंकि एमडी 5 टूटा हुआ है और वास्तव में कभी भी इसका उपयोग नहीं किया जाना चाहिए:

[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.sha256()))
    for fname in fnamelst]

फिर, आप [:16] को hash_bytestr_iter(...) कॉल करने के बाद डाल सकते हैं यदि आप केवल 128 बिट्स पाचन के लायक चाहते हैं।


मैं स्पष्ट रूप से कुछ भी मूल रूप से नया नहीं जोड़ रहा हूं, लेकिन इससे पहले कि मैं स्थिति पर टिप्पणी करने के लिए यह उत्तर दे रहा हूं :-), साथ ही कोड क्षेत्र चीजों को और स्पष्ट बनाते हैं - वैसे भी, विशेष रूप से Omnifarious के उत्तर से @ निमो के प्रश्न का उत्तर देने के लिए:

मैं चेकसम के बारे में कुछ सोच रहा था (यहां विशेष रूप से ब्लॉक आकारों पर सुझावों की तलाश में आया), और पाया है कि यह विधि आपके अपेक्षा से तेज़ी से हो सकती है। सबसे तेज़ (लेकिन सुंदर सामान्य) timeit.timeit या /usr/bin/time परिणाम को लगभग एक फ़ाइल की जांच करने के कई तरीकों से लेना। 11MB:

$ ./sum_methods.py
crc32_mmap(filename) 0.0241742134094
crc32_read(filename) 0.0219960212708
subprocess.check_output(['cksum', filename]) 0.0553209781647
md5sum_mmap(filename) 0.0286180973053
md5sum_read(filename) 0.0311000347137
subprocess.check_output(['md5sum', filename]) 0.0332629680634
$ time md5sum /tmp/test.data.300k
d3fe3d5d4c2460b5daacc30c6efbc77f  /tmp/test.data.300k

real    0m0.043s
user    0m0.032s
sys     0m0.010s
$ stat -c '%s' /tmp/test.data.300k
11890400

तो, ऐसा लगता है कि दोनों पायथन और / usr / bin / md5sum 11MB फ़ाइल के लिए लगभग 30ms लेते हैं। प्रासंगिक md5sum फ़ंक्शन (उपर्युक्त सूची में md5sum_read ) Omnifarious के समान ही है:

import hashlib
def md5sum(filename, blocksize=65536):
    hash = hashlib.md5()
    with open(filename, "rb") as f:
        for block in iter(lambda: f.read(blocksize), b""):
            hash.update(block)
    return hash.hexdigest()

माना जाता है कि ये एकल रनों से हैं ( mmap हमेशा mmap होते हैं जब कम से कम कुछ दर्जन रन बनाए जाते हैं), और बफर समाप्त हो जाने के बाद आमतौर पर मेरा अतिरिक्त f.read(blocksize) है, लेकिन यह उचित रूप से दोहराने योग्य है और दिखाता है कि कमांड लाइन पर md5sum एक पायथन कार्यान्वयन की तुलना में जरूरी नहीं है ...

संपादित करें: लंबे विलंब के लिए क्षमा करें, कुछ समय में इसे नहीं देखा है, लेकिन @ एड्रैंडल के प्रश्न का उत्तर देने के लिए, मैं एक एडलर 32 कार्यान्वयन लिखूंगा। हालांकि, मैंने इसके लिए मानक नहीं चलाए हैं। यह मूल रूप से सीआरसी 32 जैसा ही होता है: zlib.adler32() , अपडेट और डायजेस्ट कॉल की बजाय, सबकुछ एक zlib.adler32() कॉल है:

import zlib
def adler32sum(filename, blocksize=65536):
    checksum = zlib.adler32("")
    with open(filename, "rb") as f:
        for block in iter(lambda: f.read(blocksize), b""):
            checksum = zlib.adler32(block, checksum)
    return checksum & 0xffffffff

ध्यान दें कि यह रिक्त स्ट्रिंग के साथ शुरू होना चाहिए, क्योंकि एडलर रकम शून्य से शुरू होने पर वास्तव में भिन्न होते हैं, "" 1 - सीआरसी इसके बजाय 0 शुरू हो सकता है। इसे 32-बिट हस्ताक्षरित पूर्णांक बनाने के लिए AND -िंग की आवश्यकता होती है, जो सुनिश्चित करता है कि यह पाइथन संस्करणों में समान मान देता है।







hashlib