【问题标题】:Calculate md5 on the fly while reading large text file在读取大型文本文件时即时计算 md5
【发布时间】:2016-12-27 18:07:31
【问题描述】:

更新问题

我知道如何使用 python 从文件 http://docs.python.org/3.5/library/hashlib.html#hash-algorithms 创建 md5 哈希。 我也知道如何逐行读取文本文件。 但是我的文件可能会变大,并且从头到尾读取两次文件是低效。我想知道是否可以只从磁盘读取一次数据,并且像在流/管道中一样,智能地组合这两个任务。可能是这样的:

  1. 初始化 md5
  2. 以二进制模式打开文件
  3. 将一大块数据(例如 buffer_size=65536)读入缓冲区
  4. 用刚刚读取的块更新 md5
  5. 将缓冲区提供给另一个流以继续处理数据
  6. 使用TextIOWrapper(?)再次读取数据,但这次是文本
  7. 逐行阅读文本。当缓冲区被消耗时,向底层请求更多数据,直到 EOF。它会读取更多的二进制数据,更新 md5,提供新的缓冲区......我可以继续逐行读取(这就像:从第 3 步重复直到 EOF)
  8. 在 EOF 上,我已经逐行处理了我的所有文本,并拥有 md5

目标是通过将二进制 md5 计算和基于文本的处理智能地结合在同一个文件上来提高效率,只需从磁盘读取一次(而不是两次)(而不是两次)(大)文件。

我希望这能更好地解释它。再次感谢您的帮助。

于尔根

【问题讨论】:

  • 这个页面我知道并且我以前读过它。但是它到底在哪里描述了我想使用我为 md5 读取的相同缓冲区,在那里逐行读取文本?
  • 看我的问题不是md5。我的问题是a)从二进制文件中读取缓冲区b)对缓冲区做一些事情c)使用该缓冲区(这是字节而不是字符串)逐行读取那里的文本。你没有一个可行的例子吗?

标签: python file io md5


【解决方案1】:

是的,只需创建一个 hashlib.md5() object 并使用每个块更新它:

md5sum = hashlib.md5()

buffer_size = 2048  # 2kb, adjust as needed.

with open(..., 'rb') as fileobj:
    # read a binary file in chunks
    for chunk in iter(lambda: fileobj.read(buffer_size), b''):
        # update the hash object
        md5sum.update(chunk)

# produce the final hash digest in hex.
print(md5sum.hexdigest())

如果您还需要以文本形式读取数据,则必须编写自己的包装器:

  • 实现TextIOBase API(实现所有与读取相关的stub methods),并在每次请求一行时从open(..., 'rb')调用产生的BufferedIOReader对象中提取数据。那时您必须自己进行行拆分和解码。

  • 或者实现BufferedIOBase API(再次实现所有存根方法),并将其作为缓冲区传递给TextIOWrapper class

【讨论】:

  • 这正是我的问题。我知道如何创建 md5 哈希。但我对所需的 TextIOBase、BufferedOOBase 和 TextIOWrapper 部分感到困惑。你没有一个例子吗?
  • @Juergen:你能分享你在这个问题上的尝试吗?帮助纠正错误比从头开始写东西要容易得多。我今天时间不多,可能要等到明天才能看。
【解决方案2】:

这似乎适用于 python 3.6

#!/usr/bin/env python

import io
import hashlib

class MD5Pipe(io.BytesIO):
    def __init__(self, fd):
        self.fd = fd
        self.hasher = hashlib.md5()
    def readinto(self, b):
        l = self.fd.readinto(b)
        # print("readinto: ", l, len(b))
        if l > 0:
            self.hasher.update(b[0:l])
        return l
    def hexdigest(self):
        return self.hasher.hexdigest()

blocksize = 65536
file = "c:/temp/PIL/VTS/VTS_123.csv"
with open(file, "rb") as fd:
    with MD5Pipe(fd) as md5:
        with io.BufferedReader(md5) as br:
            with io.TextIOWrapper(br, newline='', encoding="utf-8") as reader:
                for line in reader:
                    print("line: ", line, end="")

                print("md5: ", md5.hexdigest())

【讨论】:

    猜你喜欢
    • 2017-12-01
    • 1970-01-01
    • 2015-12-18
    • 2016-07-27
    • 1970-01-01
    • 2016-05-26
    • 1970-01-01
    • 2021-12-05
    • 2014-06-20
    相关资源
    最近更新 更多