Генерация контрольной суммы MD5 файла
есть ли простой способ генерации (и проверки) контрольных сумм MD5 списка файлов в Python? (У меня есть небольшая программа, Я работаю, и я хотел бы подтвердить, контрольные суммы файлов).
3 ответов
вы можете использовать hashlib.md5()
обратите внимание, что иногда вы не сможете поместить весь файл в память. В этом случае вам придется последовательно читать куски 4096 байт и передавать их функции Md5:
def md5(fname):
hash_md5 = hashlib.md5()
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
есть способ, который довольно памяти неэффективное.
один файл:
import hashlib
def file_as_bytes(file):
with file:
return file.read()
print hashlib.md5(file_as_bytes(open(full_path, 'rb'))).hexdigest()
список файлов:
[(fname, hashlib.md5(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]
но, MD5, как известно, сломан и (IMHO) должен прийти со страшными предупреждениями об осуждении и удален из библиотеки, так что вот как вы должны это сделать:
[(fname, hashlib.sha256(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]
если вы хотите только 128 бит дайджеста, вы можете сделать .digest()[:16]
.
это даст вам список кортежей, каждый кортеж, содержащий имя файла и его хэш.
снова я сильно сомневаюсь в вашем использовании MD5. Вы должны хотя бы использовать SHA1. Некоторые люди думают, что пока вы не используете MD5 для 'шифрования' ты в порядке. Но материал имеет тенденцию в конечном итоге быть более широким по охвату, чем вы изначально ожидаете, и ваш случайный анализ уязвимости может оказаться полностью ошибочным. Лучше всего просто привыкнуть использовать правильный алгоритм выхода из ворот. Это просто набирать другую кучу письма-это все. Это не так уж сложно.
вот способ, который является более сложным, но эффективная память:
import hashlib
def hash_bytestr_iter(bytesiter, hasher, ashexstr=False):
for block in bytesiter:
hasher.update(block)
return (hasher.hexdigest() if ashexstr else hasher.digest())
def file_as_blockiter(afile, blocksize=65536):
with afile:
block = afile.read(blocksize)
while len(block) > 0:
yield block
block = afile.read(blocksize)
[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.md5()))
for fname in fnamelst]
и, опять же, поскольку MD5 сломан и больше не должен использоваться:
[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.sha256()))
for fname in fnamelst]
опять же, вы можете поставить [:16]
после вызова hash_bytestr_iter(...)
если вы хотите только 128 бит дайджеста.
я явно не добавляю ничего принципиально нового, но добавил этот ответ, прежде чем я был до статуса комментирования: -), плюс регионы кода делают вещи более ясными-во всяком случае, в частности, чтобы ответить на вопрос @Nemo из ответа Omnifarious:
я немного думал о контрольных суммах (пришел сюда в поисках предложений по размерам блоков, в частности) и обнаружил, что этот метод может быть быстрее, чем вы ожидали. Принимая самый быстрый (но довольно типичный) timeit.timeit
или /usr/bin/time
результат каждого из нескольких методов контрольной суммы файла ок. 11МБ:
$ ./sum_methods.py
crc32_mmap(filename) 0.0241742134094
crc32_read(filename) 0.0219960212708
subprocess.check_output(['cksum', filename]) 0.0553209781647
md5sum_mmap(filename) 0.0286180973053
md5sum_read(filename) 0.0311000347137
subprocess.check_output(['md5sum', filename]) 0.0332629680634
$ time md5sum /tmp/test.data.300k
d3fe3d5d4c2460b5daacc30c6efbc77f /tmp/test.data.300k
real 0m0.043s
user 0m0.032s
sys 0m0.010s
$ stat -c '%s' /tmp/test.data.300k
11890400
Итак, похоже, что Python и / usr/bin / md5sum занимают около 30 мс для файла 11 Мб. Соответствующий