Utiliser hashlib pour calculer md5 digest d'un fichier en Python 3
avec python 2.7 le code suivant calcule l'hexdigest mD5 du contenu d'un fichier.
(EDIT: eh bien, pas vraiment, puisque les réponses ont montré, j'ai juste pensé).
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()
maintenant, si j'exécute ce code en utilisant python3, il relance une Exception TypeError:
d.update(buf)
TypeError: object supporting the buffer API required
j'ai compris que je pouvais faire tourner ce code avec à la fois python2 et python3 le changeant en:
def md5sum(filename):
f = open(filename, mode='r')
d = hashlib.md5()
for buf in f.read(128):
d.update(buf.encode())
return d.hexdigest()
maintenant je me demande encore pourquoi le code original a cessé de fonctionner. Il semble que lors de l'ouverture d'un fichier en utilisant le modificateur de mode binaire, il renvoie des entiers au lieu de chaînes encodées en octets (je dis cela parce que type(buf) renvoie int). Est ce comportement est expliqué quelque part ?
3 réponses
je pense que vous vouliez que la for-loop fasse des appels successifs à f.read(128)
. Qui peut être fait à l'aide de iter () et functools.partielle():
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'))
for buf in f.read(128):
d.update(buf)
.. les mises à jour de la table de hachage successivement avec chacun des 128 premiers octets valeurs du fichier. Depuis l'itération sur un bytes
produit int
objects, vous recevez les appels suivants qui causent l'erreur que vous avez rencontrée dans Python3.
d.update(97)
d.update(98)
d.update(99)
d.update(100)
qui n'est pas ce que vous voulez.
au Lieu de cela, vous voulez:
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()
j'ai finalement changé mon code pour la version ci-dessous (que je trouve facile à comprendre), après avoir posé la question. Mais je vais probablement le changer pour la version suggérée par Raymond Hetting unsing functools.partiel.
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()