为什么Python计算的“hashlib.sha1”和“git hash-object”对于一个文件来说不同?

2024-09-19 14:23:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在计算一个文件的SHA-1值。

我编造了这个剧本:

def hashfile(filepath):
    sha1 = hashlib.sha1()
    f = open(filepath, 'rb')
    try:
        sha1.update(f.read())
    finally:
        f.close()
    return sha1.hexdigest()

对于一个特定的文件,我得到这个散列值:
8c3e109ff260f7b11087974ef7bcdbdc69a0a3b9
但是当我用git hash对象计算值时,我得到这个值:d339346ca154f6ed9e92205c3c5c38112e761eb7

它们为什么不同?我是做错了什么,还是我可以忽略两者的区别?


Tags: 文件closereaddefupdateopensha1hashlib
2条回答

作为参考,这里有一个更简洁的版本:

def sha1OfFile(filepath):
    import hashlib
    with open(filepath, 'rb') as f:
        return hashlib.sha1(f.read()).hexdigest()

再想一想:虽然我从未见过,但我认为有可能f.read()返回的文件比完整文件少,或者有可能返回许多GB的文件,使f.read()耗尽内存。对于每个人的启迪,让我们考虑一下如何解决这个问题:第一个解决方法是:

def sha1OfFile(filepath):
    import hashlib
    sha = hashlib.sha1()
    with open(filepath, 'rb') as f:
        for line in f:
            sha.update(line)
        return sha.hexdigest()

然而,根本不能保证'\n'出现在文件中,因此for循环将给我们以'\n'结尾的文件块这一事实可能会给我们带来与原来相同的问题。遗憾的是,我没有看到任何类似的python方法来迭代尽可能大的文件块,我认为,这意味着我们陷入了while True: ... break循环和块大小的幻数:

def sha1OfFile(filepath):
    import hashlib
    sha = hashlib.sha1()
    with open(filepath, 'rb') as f:
        while True:
            block = f.read(2**10) # Magic number: one-megabyte blocks.
            if not block: break
            sha.update(block)
        return sha.hexdigest()

当然,谁说我们可以存储1兆字节的字符串。我们也许可以,但是如果我们在一台微型嵌入式计算机上呢?

我希望我能想出一个更干净的方法,保证不会在巨大的文件上耗尽内存,而且没有神奇的数字,而且性能和最初的简单Pythonic解决方案一样好。

git计算散列如下:

sha1("blob " + filesize + "\0" + data)

Reference

相关问题 更多 >