在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中生成文件的校验和的主要内容,如果未能解决你的问题,请参考以下文章

生成文本文件的 MD5 校验和值

2.7校验和与核实

python django 中生成 Authorization token

Hadoop中的CRC数据校验文件

如何在xml中生成schema约束

在 python 中为大文件创建校验和的最快方法