使用python 2.7,以下代码计算文件内容的mD5 hexdigest。
(编辑:嗯,不是因为答案已经显示,我只是这么认为)。
import hashlib
def md5sum(filename):
f = open(filename, mode='rb')
d = hashlib.md5()
for buf in f.read(128):
d.update(buf)
return d.hexdigest()
现在,如果我使用python3运行该代码,则会引发TypeError异常:
d.update(buf)
TypeError: object supporting the buffer API required
我发现我可以使用python2和python3运行代码,将其更改为:
def md5sum(filename):
f = open(filename, mode='r')
d = hashlib.md5()
for buf in f.read(128):
d.update(buf.encode())
return d.hexdigest()
现在我仍然想知道为什么原始代码停止工作。看来,当使用二进制模式修饰符打开文件时,它返回整数而不是编码为字节的字符串(我说因为type(buf)返回int)。是否在某处解释了这种行为?
答案 0 :(得分:28)
我认为您希望for循环能够连续调用f.read(128)
。这可以使用 iter()和 functools.partial()完成:
import hashlib
from functools import partial
def md5sum(filename):
with open(filename, mode='rb') as f:
d = hashlib.md5()
for buf in iter(partial(f.read, 128), b''):
d.update(buf)
return d.hexdigest()
print(md5sum('utils.py'))
答案 1 :(得分:10)
for buf in f.read(128):
d.update(buf)
..使用文件的前128个字节值中的每一个顺序更新散列。由于迭代bytes
生成int
个对象,您将获得以下调用,这些调用会导致您在Python3中遇到错误。
d.update(97)
d.update(98)
d.update(99)
d.update(100)
这不是你想要的。
相反,你想要:
def md5sum(filename):
with open(filename, mode='rb') as f:
d = hashlib.md5()
while True:
buf = f.read(4096) # 128 is smaller than the typical filesystem block
if not buf:
break
d.update(buf)
return d.hexdigest()
答案 2 :(得分:1)
在提问之后,我终于将我的代码更改为下面的版本(我觉得很容易理解)。但我可能会将其更改为Raymond Hetting unsing functools.partial建议的版本。
import hashlib
def chunks(filename, chunksize):
f = open(filename, mode='rb')
buf = "Let's go"
while len(buf):
buf = f.read(chunksize)
yield buf
def md5sum(filename):
d = hashlib.md5()
for buf in chunks(filename, 128):
d.update(buf)
return d.hexdigest()