在python中生成文件的校验和
Posted
技术标签:
【中文标题】在python中生成文件的校验和【英文标题】:Generating a checksum of a file in python 【发布时间】:2016-11-04 08:24:28 【问题描述】:这个问题已经在这个网站上被问过并回答了很多次,但由于一些模糊的原因,没有人想出一个相对简单(在我看来)、更简洁、可能更优雅的解决方案。也许是因为解决方案实际上很糟糕,但这就是我想要弄清楚的,如果它很糟糕,那么我想知道如何以及为什么。 最受欢迎的答案之一是:
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()
这是可以理解的——我们不想将整个文件加载到内存中,所以我们在迭代器和 lambda 函数的帮助下分块读取它。很好很简单。 但大概我们可以通过如下定义 md5sum 函数以更简单的方式做到这一点:
def md5sum(fname):
md5 = hashlib.md5()
with open(fname, 'rb') as f:
for chunk in f:
md5.update(chunk)
return md5.hexdigest()
方便地,对打开的文件句柄进行迭代会为我们提供一系列行,因此我们可以使用 open(fname, 'rb')
中的“b”前缀来迭代字节对象。这样做有什么问题?
【问题讨论】:
这可能与您正在处理的文件类型有关,特别是它实际上是 ascii 文件还是二进制文件。原始版本对块大小提供了更多控制,而您的版本则受制于此处和那里的换行符。此外,为了处理大文件,我不仅一次使用 4K 数据,而且至少使用 100K,只是为了确保“分块”中没有显着的开销。我曾经有过使用 zip 模块的经验,今天 100K 不算什么。 @Dr.V 我明白了,我几乎同意你所说的一切,但据我所知,它适用于各种文件。 @weeCoder 尝试创建一个 not 包含\x0a
字节的大文件,然后查看... for chunk in f
降级为 chunk = f.read()
读取整个文件进入记忆。
@PM2Ring 哦,谢谢,这几乎回答了我的问题。如果您认为它对其他人有任何用处,您应该将其发布为答案。
【参考方案1】:
V 博士在 cmets 中所说的是正确的。
使用for chunk in f:
对以b'\n
' == b'\x0A'
结尾的块进行操作。这使得文本文件的块大小非常小,对于典型的二进制文件完全不可预测:二进制文件可能不包含 any 0A
字节。当这种情况发生时,for chunk in f:
只是将整个文件读入一个块中。
4k 的块大小应该没问题,但您可以尝试 64k 或 128k 的块大小,看看是否能提高速度。在简单的数据复制测试(使用dd
)中,我发现使用更大的块大小没有什么好处;请记住,现代操作系统擅长文件缓冲和缓存。 OTOH,我正在运行一台相当旧的 32 位单核机器。
关于散列大文件的主题,您可能对a program I wrote 感兴趣,它使用 OpenSSL 加密库对大文件执行 SHA256 散列。这个程序的特点是它是可恢复的:你可以随时停止它,当你重新启动它时它会继续哈希过程。
而here's one 使用hashlib
同时计算文件的MD5 和SHA256 哈希值。
【讨论】:
以上是关于在python中生成文件的校验和的主要内容,如果未能解决你的问题,请参考以下文章