Мой текущий подход таков:
def get_hash(path=PATH, hash_type='md5'):
func = getattr(hashlib, hash_type)()
with open(path, 'rb') as f:
for block in iter(lambda: f.read(1024*func.block_size, b''):
func.update(block)
return func.hexdigest()
Для вычисления md5sum iso-файла размером 842 МБ на i5 @ 1,7 ГГц требуется около 3,5 секунд. Я пробовал разные способы чтения файла, но все они дают более медленный результат. Возможно, есть более быстрое решение?
РЕДАКТИРОВАТЬ: я заменил 2**16
(внутри f.read()
) на 1024*func.block_size
, так как block_size
по умолчанию для большинства функций хеширования, поддерживаемых hashlib, равно 64
(за исключением 'sha384' и 'sha512' - для них block_size
по умолчанию равно 128
). Поэтому размер блока остался прежним (65536 бит).
РЕДАКТИРОВАТЬ (2): я сделал что-то не так. Это занимает 8,4 секунды вместо 3,5. :(
РЕДАКТИРОВАТЬ (3): по-видимому, Windows использовала диск на + 80%, когда я снова запустил функцию. Это действительно занимает 3,5 секунды. Фу.
Другое решение (~-0,5 секунды, немного быстрее) — использовать os.open():
def get_hash(path=PATH, hash_type='md5'):
func = getattr(hashlib, hash_type)()
f = os.open(path, (os.O_RDWR | os.O_BINARY))
for block in iter(lambda: os.read(f, 2048*func.block_size), b''):
func.update(block)
os.close(f)
return func.hexdigest()
Обратите внимание, что эти результаты не являются окончательными.
md5sum
? - person   schedule 29.03.2014os.open()
, если вы еще не используете его. - person martineau   schedule 29.03.2014open()
, которая возвращает файловый объект, что звучит как своего рода оболочка, поэтому использование первого может повлечь за собой меньшие накладные расходы. - person martineau   schedule 29.03.2014os.read()
. - person martineau   schedule 29.03.2014