【问题标题】:Why is the Python calculated "hashlib.sha1" different from "git hash-object" for a file?为什么 Python 计算的“hashlib.sha1”与文件的“git hash-object”不同?
【发布时间】:2010-12-24 14:27:01
【问题描述】:

我正在尝试计算文件的 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_object 计算值时,我得到这个值:d339346ca154f6ed9e92205c3c5c38112e761eb7

它们为什么不同?我做错了什么,还是我可以忽略其中的差异?

【问题讨论】:

  • 如果您打算同时使用哈希值,就不能真正忽略其中的区别。
  • 忘了说,只是用git作为参考,不打算一起用。
  • 如果文件可能非常大,您可以一次处理一个块,这样您就不需要一次在 RAM 中处理整个文件:stackoverflow.com/questions/7829499/…
  • How does git compute file hashes? 的可能重复 最小示例 ;-)

标签: python git hash


【解决方案1】:

git 像这样计算哈希:

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

Reference

【讨论】:

  • 没有问题,引用的链接很不一样,碰巧找到了。
  • 需要说明的是,git这样做是为了避免长度扩展攻击。
  • 这个建议的完整实现可以在问题Assigning Git SHA1's without Git中找到。
【解决方案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' 结尾的文件块这一事实可能会给我们带来与最初相同的问题.可悲的是,我没有看到任何类似的 Pythonic 方法来迭代尽可能大的文件块,我认为这意味着我们陷入了 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 解决方案一样好。

【讨论】:

  • 再想一想,如果 f.read() 不能返回整个文件(例如,在多 GB 文件的情况下),这可能会出现问题,因此它可能应该遍历块。
猜你喜欢
  • 2011-07-14
  • 2017-12-19
  • 1970-01-01
  • 1970-01-01
  • 2014-01-05
  • 1970-01-01
  • 2012-08-05
  • 1970-01-01
  • 2015-03-01
相关资源
最近更新 更多