Использование hashlib для вычисления md5-дайджеста файла в Python 3

StackOverflow https://stackoverflow.com/questions/7829499

  •  27-10-2019
  •  | 
  •  

Вопрос

С помощью python 2.7 следующий код вычисляет шестнадцатеричное значение mD5 содержимого файла.

(РЕДАКТИРОВАТЬ:ну, не совсем так, как показали ответы, я просто так подумал).

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).Объясняется ли где - нибудь такое поведение ?

Это было полезно?

Решение

Я думаю, вы хотели, чтобы цикл for выполнял последовательные вызовы f.read(128).Это можно сделать с помощью iter() и функции.частичный():

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)

..обновляет хэш последовательно с каждым из первых 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()

Я, наконец, изменил свой код на приведенную ниже версию (которую я нахожу легкой для понимания) после того, как задал вопрос.Но я, вероятно, изменю его на версию, предложенную 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()
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top