在读取大文本文件时动态计算md5

时间:2016-12-27 18:07:31

标签: python file io md5

更新的问题

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

  1. 初始化md5
  2. 以二进制模式打开文件
  3. 将一大块数据(例如buffer_size = 65536)读入缓冲区
  4. 使用刚读取的块
  5. 更新md5
  6. 将缓冲区提供给另一个流以继续处理数据
  7. 使用TextIOWrapper(?)再次读取数据,但这次是文本
  8. 逐行阅读文字。消耗缓冲区时,请询问底层以获取更多数据,直到EOF。它会读取更多的二进制数据,更新md5,提供新的缓冲区......我可以继续逐行阅读(这就像:从第3步重复到EOF)
  9. 在EOF上,我已逐行处理了所有文本,并拥有md5
  10. 目标是通过在同一文件上智能地结合二进制md5计算和基于文本的处理,从光盘中读取(大)文件一次而不是两次来提高效率。

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

    尔根

2 个答案:

答案 0 :(得分: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),并从BufferedIOReader调用生成的open(..., 'rb')对象中提取数据每次请求一行。您必须在此时进行自己的行拆分和解码。

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

答案 1 :(得分:1)

这似乎适用于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())