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?

È stato utile?

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()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top