有没有一种简单的方法在 Python 中生成(和检查)文件列表的 MD5 校验和?(我正在开发一个小程序,想要确认文件的校验和。)
你可以使用hashlib.md5()
注意,有时您可能无法将整个文件放入内存中。在这种情况下,您需要按顺序读取4096字节的块,并将它们提供给md5
方法:
import hashlib
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()
注意: hash_md5.hexdigest()
将返回摘要的十六进制字符串表示形式,如果您只需要打包的字节,请使用 return hash_md5.digest()
,这样您不必进行转换。
有一种方法非常费内存。
单文件:
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已经被破解,不应用于任何目的,因为漏洞分析可能非常棘手,并且无法分析代码可能出现的任何安全问题。在我看来,它应该从库中彻底删除,以便强制每个使用它的人进行更新。因此,以下是您应该执行的操作:
[(fname, hashlib.sha256(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]
.digest()[:16]
。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答案的问题,我已经添加了这个答案,而且代码区域使事情更加清晰--无论如何:
我碰巧在思考一些校验和方面的问题(特别是在寻找有关块大小建议的建议时来到这里),并发现这种方法可能比您预期的要快。从几种校验文件大小约为11MB的文件的最快(但相当典型的)timeit.timeit
或/usr/bin/time
结果中选取:
$ ./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 毫秒来处理一个 11MB 的文件。相关的 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()
尽管如此,这些都是来自单个运行的数据(当至少进行几十次运行时,mmap
的运行速度总是略快一些),而我的代码通常在缓冲区耗尽后会多运行一次f.read(blocksize)
。但它是可以重复的,表明命令行上的md5sum
并不一定比Python实现更快...
编辑:很抱歉让大家等这么久,我已经有一段时间没有看过这个问题了,但为了回答@EdRandall的问题,我会写下一个Adler32的实现。然而,我还没有对其进行基准测试。它基本上与CRC32相同:除了初始化、更新和摘要调用之外,所有内容都是一个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
请注意,这必须从空字符串开始,因为 Adler 总和从零开始与其在 ""
的总和确实不同,后者为 1
-- CRC 可以以 0
开头。需要使用 AND
运算使其成为一个32位无符号整数,这可以确保在 Python 版本之间返回相同的值。:=
(与hashlib
一起使用)。import hashlib
with open("your_filename.txt", "rb") as f:
file_hash = hashlib.md5()
while chunk := f.read(8192):
file_hash.update(chunk)
print(file_hash.digest())
print(file_hash.hexdigest()) # to get a printable str instead of bytes
考虑使用 hashlib.blake2b
替代 md5
(只需在上述代码段中将 md5
替换为 blake2b
)。它是加密安全的,比 MD5 更快速。
hashlib.md5(pathlib.Path('path/to/file').read_bytes()).hexdigest()
import hashlib
with open(path, "rb") as f:
digest = hashlib.file_digest(f, "md5")
print(digest.hexdigest())
simple-file-checksum
1,它仅使用subprocess
调用 openssl
(macOS/Linux)或 CertUtil
(Windows),并从输出中仅提取摘要。
pip install simple-file-checksum
>>> from simple_file_checksum import get_checksum
>>> get_checksum("path/to/file.txt")
'9e107d9d372bb6826bd81d3542a419d6'
>>> get_checksum("path/to/file.txt", algorithm="MD5")
'9e107d9d372bb6826bd81d3542a419d6'
支持使用SHA1
、SHA256
、SHA384
和SHA512
算法。
1披露:我是simple-file-checksum
的作者。
你可以在这里使用 shell。
from subprocess import check_output
#for windows & linux
hash = check_output(args='md5sum imp_file.txt', shell=True).decode().split(' ')[0]
#for mac
hash = check_output(args='md5 imp_file.txt', shell=True).decode().split('=')[1]
将file_path
更改为您的文件路径
import hashlib
def getMd5(file_path):
m = hashlib.md5()
with open(file_path,'rb') as f:
lines = f.read()
m.update(lines)
md5code = m.hexdigest()
return md5code
md5sum
呢? - kennytmmd5sum
。这就是为什么有安全意识的程序员在我看来不应该使用它的原因。 - Debug255md5sum
和这个SO问题中描述的技术 - 最好使用SHA-2或SHA-3,如果可能的话:https://en.wikipedia.org/wiki/Secure_Hash_Algorithms - Per Lundberg