在Python中散列文件

use*_*300 67 python hash md5 sha1 hashlib

我想让python读取到EOF,这样我就可以得到一个合适的哈希值,无论是sha1还是md5.请帮忙.这是我到目前为止:

import hashlib

inputFile = raw_input("Enter the name of the file:")
openedFile = open(inputFile)
readFile = openedFile.read()

md5Hash = hashlib.md5(readFile)
md5Hashed = md5Hash.hexdigest()

sha1Hash = hashlib.sha1(readFile)
sha1Hashed = sha1Hash.hexdigest()

print "File Name: %s" % inputFile
print "MD5: %r" % md5Hashed
print "SHA1: %r" % sha1Hashed
Run Code Online (Sandbox Code Playgroud)

Ran*_*unt 107

TL; DR使用缓冲区不使用大量内存.

我相信,当我们考虑使用非常大的文件时的内存含义时,我们会遇到问题的症结.我们不希望这个坏男孩在2千兆字节的文件中流失2千兆字节的文件所以,正如pasztorpisti指出的那样,我们必须处理那些更大的文件!

import sys
import hashlib

# BUF_SIZE is totally arbitrary, change for your app!
BUF_SIZE = 65536  # lets read stuff in 64kb chunks!

md5 = hashlib.md5()
sha1 = hashlib.sha1()

with open(sys.argv[1], 'rb') as f:
    while True:
        data = f.read(BUF_SIZE)
        if not data:
            break
        md5.update(data)
        sha1.update(data)

print("MD5: {0}".format(md5.hexdigest()))
print("SHA1: {0}".format(sha1.hexdigest()))
Run Code Online (Sandbox Code Playgroud)

我们所做的就是在64kb块中更新这个坏男孩的哈希值,因为我们使用了hashlib的方便的花花公子更新方法.通过这种方式,我们使用的内存比2gb要少得多,因为它可以同时散列这个人!

您可以使用以下方法测试:

$ mkfile 2g bigfile
$ python hashes.py bigfile
MD5: a981130cf2b7e09f4686dc273cf7187e
SHA1: 91d50642dd930e9542c39d36f0516d45f4e1af0d
$ md5 bigfile
MD5 (bigfile) = a981130cf2b7e09f4686dc273cf7187e
$ shasum bigfile
91d50642dd930e9542c39d36f0516d45f4e1af0d  bigfile
Run Code Online (Sandbox Code Playgroud)

希望有所帮助!

所有这些都在右侧的链接问题中概述:在Python中获取大文件的MD5哈希值


附录!

通常在编写python时,它有助于养成遵循pep-8的习惯.例如,在python中,变量通常是下划线而不是camelCased.但这只是风格,没有人真正关心那些除了那些必须阅读不良风格的人之外的东西......这可能是你从现在开始阅读这段代码.


max*_*zig 39

为了正确有效地计算文件的哈希值(在Python 3中):

  • 以二进制模式打开文件(即添加'b'到文件模式)以避免字符编码和行结束转换问题.
  • 不要将完整的文件读入内存,因为这会浪费内存.相反,逐块顺序读取它并更新每个块的散列.
  • 消除双缓冲,即不使用缓冲IO,因为我们已经使用了最佳块大小.
  • 使用readinto()以避免缓冲区搅动.

例:

import hashlib

def sha256sum(filename):
    h  = hashlib.sha256()
    b  = bytearray(128*1024)
    mv = memoryview(b)
    with open(filename, 'rb', buffering=0) as f:
        for n in iter(lambda : f.readinto(mv), 0):
            h.update(mv[:n])
    return h.hexdigest()
Run Code Online (Sandbox Code Playgroud)

  • @Mitar,下限是物理块的最大值(传统上为 512 字节或较新磁盘的 4KiB)和系统页面大小(许多系统上为 4KiB,其他常见选择:8KiB 和 64 KiB)。然后你基本上做一些基准测试和/或查看已发布的[基准测试结果和相关工作](http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob;f=src/ioblksize .h;h=ed2f4a9c4d77462f357353eb73ee4306c28b37f1;hb=HEAD#l23)(例如检查当前的rsync/GNU cp/...使用什么)。 (6认同)
  • @Murmel“同等大小的文件”是什么意思?这个答案是一个通用的解决方案。如果你用“buffering=0”调用“open()”,它不会做任何缓冲。Mitar 的答案实现了缓冲区搅拌。 (3认同)
  • 你怎么知道什么是最佳块大小? (2认同)
  • 我对(1)@Randall Hunt和(2)您的解决方案(以此顺序,由于文件高速缓存而重要)的基准测试了大约116GB的文件和sha1sum算法。修改了解决方案1,以便使用20 * 4096(PAGE_SIZE)的缓冲区并将缓冲参数设置为0。仅修改了解决方案2的算法(sha256-> sha1)。结果:(1)3m37.137s(2)3m30.003s。二进制模式下的本机sha1sum:3m31.395s (2认同)
  • 澄清一下:您使用“memoryview”的唯一原因是“[:n]”,对吧?顺便说一句,从 Python 3.8 开始,也许 `while n := f.readinto(mv):` 会更清楚。 (2认同)

Mit*_*tar 8

我会简单地建议:

def get_digest(file_path):
    h = hashlib.sha256()

    with open(file_path, 'rb') as file:
        while True:
            # Reading is buffered, so we can read smaller chunks.
            chunk = file.read(h.block_size)
            if not chunk:
                break
            h.update(chunk)

    return h.hexdigest()
Run Code Online (Sandbox Code Playgroud)

这里所有其他答案似乎太复杂了。Python在读取时已经在缓冲(以理想的方式,或者如果您有更多有关基础存储的信息,则可以配置该缓冲),因此最好分块读取散列函数找到的理想值,这样可以使其更快或更省时计算哈希函数。因此,您可以使用Python缓冲来控制应该控制的内容,而不是禁用缓冲并尝试自己模拟它,即数据消费者可以找到理想的哈希块大小。

  • 该解决方案不符合简单的基准!在我的 1Gb 文件上,它比 Randall Hunt 的答案(2.18s)慢两倍多(5.38s),后者本身比 maxschlepzig 的答案(2.13s)慢一点。 (5认同)
  • “block_size”比任何有用的读取大小小得多。此外,任何有用的块和读取大小都是 2 的幂。因此,除了最后一个读取之外,所有读取的读取大小都可以除以块大小。例如,sha256 块大小为 64 字节。这意味着 update() 能够直接处理输入,而无需缓冲最多为 block_size 的任意倍数。因此,只有当最后一次读取不能被块大小整除时,它才必须一次缓冲最多 63 个字节。因此,您最后的评论是不正确的,并且不支持您在答案中提出的主张。 (3认同)
  • `hash.block_size` 被记录为“哈希算法的内部块大小”。Hashlib **没有**发现它_理想_。包文档中没有任何内容表明“update()”更喜欢“hash.block_size”大小的输入。如果你这样调用它并不会使用更少的CPU。您的“file.read()”调用会导致许多不必要的对象创建以及从文件缓冲区到新块字节对象的多余副本。 (2认同)

Ant*_*ala 8

这是一个 Python 3、POSIX 解决方案(不是 Windows!),用于mmap将对象映射到内存中。

import hashlib
import mmap

def sha256sum(filename):
    h  = hashlib.sha256()
    with open(filename, 'rb') as f:
        with mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) as mm:
            h.update(mm)
    return h.hexdigest()
Run Code Online (Sandbox Code Playgroud)

  • 我对此与逐块读取方法进行了基准测试。此方法需要 3GB 内存来哈希 3GB 文件,而 maxschlepzig 的答案需要 12MB。他们在我的 Ubuntu 机器上花费的时间大致相同。 (3认同)

phy*_*yyl 6

我编写了一个模块,它能够用不同的算法散列大文件。

pip3 install py_essentials
Run Code Online (Sandbox Code Playgroud)

像这样使用模块:

from py_essentials import hashing as hs
hash = hs.fileChecksum("path/to/the/file.txt", "sha256")
Run Code Online (Sandbox Code Playgroud)


gre*_*van 6

从Python 3.11开始,您可以使用file_digest()方法来负责读取文件:

import hashlib

with open(inputFile, "rb") as f:
    digest = hashlib.file_digest(f, "sha256")
Run Code Online (Sandbox Code Playgroud)