生成文件的MD5校验和
有什么简单的方法来生成(和检查)Python中的文件列表的MD5校验和? (我有一个小程序,我正在处理,我想确认文件的校验和)。
你可以使用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()
有一种方法是相当低效的内存。
单个文件:
print hashlib.md5(open(full_path, 'rb').read()).hexdigest()
文件列表:
import hashlib [(fname, hashlib.md5(open(fname, 'rb').read()).digest()) for fname in fnamelst]
但是,MD5是已知的中断,(恕我直言)应该带有可怕的弃用警告,并从图书馆中删除,所以这里是你应该如何做到这一点:
import hashlib [(fname, hashlib.sha256(open(fname, 'rb').read()).digest()) for fname in fnamelst]
如果只需要128位摘要,则可以执行.digest()[:16]
。
这将给你一个元组列表,每个元组包含它的文件名和它的散列。
我再次强烈质疑您使用MD5。 你至less应该使用SHA1。 有些人认为,只要你不使用MD5的“encryption”的目的,你没事。 但是事情的结果往往会比最初预期的要宽泛,而且你的偶然漏洞分析可能被certificate是完全有缺陷的。 最好是习惯使用正确的algorithm。 这只是input一堆不同的字母。 这并不难。
这是一个更复杂的方式,但是内存有效率 :
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]
同样,如果只需要128位摘要,则可以在调用hash_bytestr_iter(...)
之后放置[:16]
。
我显然没有添加任何根本性的新东西,但是在我开始评论状态之前添加了这个答案:-),再加上代码区域使事情变得更加清晰 – 无论如何,特别要回答@ Nemo从Omnifarious的回答中提出的问题:
我碰巧在考虑一下校验和(特意来这里寻找块大小的build议),并发现这种方法可能比你想象的要快。 以最快的(但非常典型的) timeit.timeit
或/usr/bin/time
结果为基础, 11MB:
$ ./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
所以,对于11MB的文件,看起来像Python和/ usr / bin / md5sum大约需要30ms。 相关的md5sum
函数(上面列出的md5sum_read
)与Omnifarious的非常相似:
import hashlib def md5sum(filename, blocksize=65536): hash = hashlib.md5() with open(filename, "rb") as f: for block in iter(lambda: f.read(blocksize), b""): hash.update(block) return hash.hexdigest()
当然,这些是单次运行的(当运行至less几十次运行时, mmap
运行速度总是较快),而我的缓冲区耗尽之后通常会得到一个额外的f.read(blocksize)
,但它是合理的可重复的,显示命令行上的md5sum
不一定比Python实现更快…
编辑:对不起,很长的延迟,有没有看过这个在一段时间,但回答@ EdRandall的问题,我会写下一个Adler32实现。 但是,我还没有为它运行的基准。 它基本上和CRC32一样:不是初始化,更新和摘要调用, zlib.adler32()
调用zlib.adler32()
:
import zlib def adler32sum(filename, blocksize=65536): checksum = zlib.adler32("") with open(filename, "rb") as f: for block in iter(lambda: f.read(blocksize), b""): checksum = zlib.adler32(block, checksum) return checksum & 0xffffffff
请注意,这必须从空string开始,因为当从零开始对它们的总和为""
1
""
时,Adler总和确实是不同的,这是1
,CRC可以从0
开始。 AND
-ing需要使其成为一个32位无符号整数,这确保它在Python版本中返回相同的值。
import os import hashlib if os.path.exists(file_path) == False: return None md5 = hashlib.md5() f = open(file_path) for line in f: md5.update(line) f.close() return md5.hexdigest()