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

时间:2017-03-15 20:02:37

标签: python hash md5 digest

我需要在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

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

在读取整个文件的同时逐行读取文件是否有任何显着改善还是必须加载整个文件来计算哈希?

3 个答案:

答案 0 :(得分:3)

当然,您可以以块的形式加载数据,这样内存使用量就会大幅下降,因为您不再需要加载整个文件。然后对每个块使用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)可调用版本。这是过于简单的,但在这种情况下仍然是正确的。

答案 1 :(得分:1)

两个片段都会得到相同的结果:

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())

一些注意事项:

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

答案 2 :(得分:1)

根据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