python on-the-fly md5作为一个读取流

时间:2012-12-23 21:30:31

标签: python python-3.x

python 3是否有用于制作过滤流的结构?特别是,我的目标是计算从REST服务读取的内容的md5校验和,而不需要额外的副本。如果我可以继承某种类型的过滤器流并将字节推送到hashlib派生的md5对象中,我会很好。

目前,我的代码包括:

shutil.copyfileobj(r.raw, outstream)

其中'r'是响应对象。我可以在r.raw周围包装一个生成器或一些这样的东西,它将被调用,每个数据缓冲区都被读取,这样我就可以将它传递给md5吗?

1 个答案:

答案 0 :(得分:6)

requests支持reading URL data in chunks,而hashlib库可让您以块的形式计算MD5,因此您已经拥有了所需的一切。您可以选择.iter_lines().iter_content()

import requests
import hashlib

r = requests.get(url, stream=True)

sig = hashlib.md5()
for line in r.iter_lines():
    sig.update(line)

print(sig.hexdigest())

如果 将其视为过滤器,请使用生成器:

class MD5TransparentFilter:
    def __init__(self, source):
        self._sig = hashlib.md5()
        self._source = source

    def __iter__(self):
        for line in self._source:
            self._sig.update(line)
            yield line

    def hexdigest(self):
        return self._sig.hexdigest()

然后在.iter_lines().iter_content()迭代器上使用它:

r = requests.get(url, stream=True)
filtered = MD5TransparentFilter(r.iter_content(1000))

for line in filtered:
    # do something with the line

print(filtered.hexdigest())

对于shutil.copyfileobj(),您需要实现.read()界面而不是.__iter__(),但原则是相同的:

class MD5TransparentFile:
    def __init__(self, source):
        self._sig = hashlib.md5()
        self._source = source

    def read(self, buffer):
        # we ignore the buffer size, just use the `.next()` value in the source iterator
        try:
            line = self._source.next()
            self._sig.update(line)
            return line
        except StopIteration:
            return b''

    def hexdigest(self):
        return self._sig.hexdigest()

MD5TransparentFile()类使用.iter_content().iter_lines()迭代器,并在每次调用时将数据返回.read(),并动态计算MD5。这可以直接用于您的shutil.copyfileobj()示例。