Pregunta

Con Python 2.7 el siguiente código calcula la hexdigest MD5 del contenido de un archivo.

(EDIT: Bueno, no realmente como respuestas han demostrado, sólo pensaba así)

.
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()

Ahora si me quedo ese código usando python3 que provocará una excepción TypeError:

    d.update(buf)
TypeError: object supporting the buffer API required

Me di cuenta de que podía hacer que el código de ejecución tanto con python2 y python3 cambiándolo 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()

Ahora todavía se preguntan por qué el código original ha dejado de funcionar. Parece que cuando se abre un archivo usando el modo binario modificador devuelve enteros en lugar de cadenas codificadas como bytes (lo digo porque tipo (BUF) int). Este comportamiento es explicado en alguna parte?

¿Fue útil?

Solución

Creo que quería que el bucle para hacer llamadas sucesivas a f.read(128). Eso se puede hacer uso de iter () y 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'))

Otros consejos

for buf in f.read(128):
  d.update(buf)

.. actualiza el hash secuencialmente con cada uno de los primeros 128 bytes valores del archivo. Desde la iteración sobre un bytes produce objetos int, se obtienen los siguientes llamadas que causan el error que encontraste en python3.

d.update(97)
d.update(98)
d.update(99)
d.update(100)

que no es lo que desea.

En su lugar, usted quiere:

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()

Finalmente cambió mi código para la versión más abajo (que me resulta fácil de entender), después de hacer la pregunta. Pero probablemente el cambio a la versión sugerida por functools.partial Raymond hetting unsing.

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()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top