Utilizzando hashlib Per calcolare digest MD5 di un file in Python 3
-
27-10-2019 - |
Domanda
Con Python 2.7 il seguente codice calcola il hexdigest MD5 del contenuto di un file.
(EDIT: Beh, non proprio come le risposte hanno dimostrato, ho pensato così)
.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()
Ora, se io corro che il codice usando python3 si solleva un'eccezione TypeError:
d.update(buf)
TypeError: object supporting the buffer API required
ho capito che avrei potuto fare che eseguire codice con entrambe python2 e python3 cambiarla a:
def md5sum(filename):
f = open(filename, mode='r')
d = hashlib.md5()
for buf in f.read(128):
d.update(buf.encode())
return d.hexdigest()
Ora mi chiedo ancora perché il codice originale ha smesso di funzionare. Sembra che quando si apre un file utilizzando la modalità binaria modificatore restituisce numeri interi, invece di stringhe codificate come byte (Lo dico perché di tipo (BUF) restituisce int). È questo comportamento ha spiegato qualche parte?
Soluzione
Credo che si voleva il ciclo for per effettuare chiamate successive alla f.read(128)
. Ciò può essere fatto utilizzando iter () e 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'))
Altri suggerimenti
for buf in f.read(128):
d.update(buf)
.. aggiorna l'hash in sequenza con ciascuno dei primi 128 bytes i valori del file. Dal momento che l'iterazione su un bytes
produce oggetti int
, si ottengono i seguenti chiamate che causano l'errore che si è verificato in python3.
d.update(97)
d.update(98)
d.update(99)
d.update(100)
che non è quello che si desidera.
Invece, si vuole:
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()
Alla fine ho cambiato il mio codice per la versione di sotto (che trovo facile da capire) dopo aver chiesto la questione. Ma io probabilmente cambiare alla versione suggerita da Raymond hetting Conuna 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()