在 Python 中获取文件的哈希(摘要) - 一次读取整个文件与逐行读取



我需要在Python中获取文件的哈希(摘要(。

通常,在处理任何文件内容时,由于内存问题,建议逐行逐步处理,但我需要加载整个文件才能获得其摘要。

目前我以这种方式获取哈希:

import hashlib
def get_hash(f_path, mode='md5'):
    h = hashlib.new(mode)
    with open(f_path, 'rb') as file:
        data = file.read()
    h.update(data)
    digest = h.hexdigest()
    return digest

有没有其他方法可以以更优化或更清洁的方式执行此操作?

当仍然必须加载整个文件来计算哈希时,逐行逐行读取文件是否比一次读取整个文件有任何显着改进

根据 hashlib.update(( 的文档,您无需担心不同哈希算法的块大小。但是,我会对此进行一些测试。但是,它似乎检查出来,512 是 MD5 的块大小,如果您将其更改为其他任何内容,结果与一次读取所有内容相同。

import hashlib
def get_hash(f_path, mode='md5'):
    h = hashlib.new(mode)
    with open(f_path, 'rb') as file:
        data = file.read()
    h.update(data)
    digest = h.hexdigest()
    return digest
def get_hash_memory_optimized(f_path, mode='md5'):
    h = hashlib.new(mode)
    with open(f_path, 'rb') as file:
        block = file.read(512)
        while block:
            h.update(block)
            block = file.read(512)
    return h.hexdigest()
digest = get_hash('large_bin_file')
print(digest)
digest = get_hash_memory_optimized('large_bin_file')
print(digest)

> bcf32baa9b05ca3573bf568964f34164
> bcf32baa9b05ca3573bf568964f34164

当然,您可以分块加载数据,这样内存使用量就会显着下降,因为您不再需要加载整个文件。然后对每个块使用 hash.update(chunk)

from functools import partial
Hash = hashlib.new("sha1")
size = 128 # just an example
with open("data.txt", "rb") as File:
    for chunk in iter(partial(f.read, size), b''):
        Hash.update(chunk)

我发现这个iter技巧非常整洁,因为它允许编写更干净的代码。一开始可能看起来很混乱,所以我将解释它是如何工作的:

  • iter(function, sentinel)连续执行function并生成它返回的值,直到其中一个等于 sentinel
  • partial(f.read, size)返回 f.read(size)可调用版本。这过于简化,但在这种情况下仍然正确。

使用两个代码段,您会得到相同的结果:

h = hashlib.new("md5")
with open(filename,"rb") as f:
    for line in f:
        h.update(line)
print(h.hexdigest())

h = hashlib.new("md5")
with open(filename,"rb") as f:
    h.update(f.read())
print(h.hexdigest())

一些注意事项:

  • 第一种方法最适合大文本文件,内存方面。使用二进制文件,没有"行"这样的东西。不过,它会起作用,但"块"方法更常规(不打算解释其他答案(
  • 如果文件很大,第二种方法会消耗大量内存
  • 在这两种情况下,请确保以二进制模式打开文件,否则行尾转换可能会导致错误的校验和(外部工具将计算与程序不同的 MD5(

最新更新