2013-06-11 22 views
1

我今天在一個簡單的腳本中使用了所有可用的hashlib算法(md5,sha1 .....)中的校驗和文件,我用Python2編寫了它並進行了調試,但當我決定將它移植到Python 3時,它就無法工作。有趣的是,它適用於小文件,但不適用於大文件。我認爲緩衝文件的方式有問題,但錯誤信息是什麼使我認爲它與我正在做的十六進制文件的方式有關(我認爲)這是我的整個腳本的副本,所以隨意複製,使用它,並幫助我找出問題所在。 checksuming一個250 MB的文件時,我得到的錯誤是使用Python2但不使用Python 3的腳本(hashlib)

「在第10位 'UTF-8' 編解碼器不能解碼字節0xf3:無效延續字節」 我google一下

,但可找不到任何修復它的東西。此外,如果你看到更好的方法來優化它,請讓我知道。我的主要目標是使工作100%在Python 3.感謝

#!/usr/local/bin/python33 
import hashlib 
import argparse 

def hashFile(algorithm = "md5", filepaths=[], blockSize=4096): 
    algorithmType = getattr(hashlib, algorithm.lower())() #Default: hashlib.md5() 
    #Open file and extract data in chunks 
    for path in filepaths: 
     try: 
      with open(path) as f: 
       while True: 
        dataChunk = f.read(blockSize) 
        if not dataChunk: 
         break 
        algorithmType.update(dataChunk.encode()) 
       yield algorithmType.hexdigest() 
     except Exception as e: 
      print (e) 

def main(): 
    #DEFINE ARGUMENTS 
    parser = argparse.ArgumentParser() 
    parser.add_argument('filepaths', nargs="+", help='Specified the path of the file(s) to hash') 
    parser.add_argument('-a', '--algorithm', action='store', dest='algorithm', default="md5", 
         help='Specifies what algorithm to use ("md5", "sha1", "sha224", "sha384", "sha512")') 
    arguments = parser.parse_args() 
    algo = arguments.algorithm 
    if algo.lower() in ("md5", "sha1", "sha224", "sha384", "sha512"): 

這裏是在Python 2工作的代碼,我只是把它如果你想使用它,而無需modigy上面的一個。

#!/usr/bin/python 
import hashlib 
import argparse 

def hashFile(algorithm = "md5", filepaths=[], blockSize=4096): 
    ''' 
    Hashes a file. In oder to reduce the amount of memory used by the script, it hashes the file in chunks instead of putting 
    the whole file in memory 
    ''' 
    algorithmType = hashlib.new(algorithm) #getattr(hashlib, algorithm.lower())() #Default: hashlib.md5() 
    #Open file and extract data in chunks 
    for path in filepaths: 
     try: 
      with open(path, mode = 'rb') as f: 
       while True: 
        dataChunk = f.read(blockSize) 
        if not dataChunk: 
         break 
        algorithmType.update(dataChunk) 
       yield algorithmType.hexdigest() 
     except Exception as e: 
      print e 

def main(): 
    #DEFINE ARGUMENTS 
    parser = argparse.ArgumentParser() 
    parser.add_argument('filepaths', nargs="+", help='Specified the path of the file(s) to hash') 
    parser.add_argument('-a', '--algorithm', action='store', dest='algorithm', default="md5", 
         help='Specifies what algorithm to use ("md5", "sha1", "sha224", "sha384", "sha512")') 
    arguments = parser.parse_args() 
    #Call generator function to yield hash value 
    algo = arguments.algorithm 
    if algo.lower() in ("md5", "sha1", "sha224", "sha384", "sha512"): 
     for hashValue in hashFile(algo, arguments.filepaths): 
      print hashValue 
    else: 
     print "Algorithm {0} is not available in this script".format(algorithm) 

if __name__ == "__main__": 
    main() 

回答

1

我還沒有嘗試過在Python 3,但我得到的Python 2.7.5二進制文件相同的錯誤(唯一的區別是,我的是用ASCII碼編解碼器)。取而代之的編碼數據塊,直接以二進制方式打開文件:

with open(path, 'rb') as f: 
    while True: 
     dataChunk = f.read(blockSize) 
     if not dataChunk: 
      break 
     algorithmType.update(dataChunk) 
    yield algorithmType.hexdigest() 

除此之外,我會使用的方法hashlib.new而不是getattr,並hashlib.algorithms_available檢查,如果論證是有效的。

+0

謝謝,我將避免hashlib.algorithms_available,因爲它只能在3.2之後,python2不可用,但hashlib.new肯定看起來更乾淨。 – JohnnyLoo

+0

順便說一句,我得到了你提到的錯誤,但我通過在更新「dataChunk」時刪除了.encode()部分來解決它。我添加的第二個腳本應該可以爲你工作 – JohnnyLoo

+0

@JuanCarlos它沒有給出任何錯誤,但它返回一個除非以二進制模式打開文件,否則不正確的md5sum。 –