Python 解压字节流?

问题描述 投票:0回答:5

情况是这样的:

  • 我从 Amazon S3 获取 gzipped xml 文档

      import boto
      from boto.s3.connection import S3Connection
      from boto.s3.key import Key
      conn = S3Connection('access Id', 'secret access key')
      b = conn.get_bucket('mydev.myorg')
      k = Key(b)
      k.key('documents/document.xml.gz')
    
  • 我在文件中将它们读为

      import gzip
      f = open('/tmp/p', 'w')
      k.get_file(f)
      f.close()
      r = gzip.open('/tmp/p', 'rb')
      file_content = r.read()
      r.close()
    

问题

如何直接解压流并读取内容?

我不想创建临时文件,它们看起来不太好。

python compression
5个回答
41
投票

是的,您可以使用

zlib
模块来解压缩字节流:

import zlib

def stream_gzip_decompress(stream):
    dec = zlib.decompressobj(32 + zlib.MAX_WBITS)  # offset 32 to skip the header
    for chunk in stream:
        rv = dec.decompress(chunk)
        if rv:
            yield rv
    if dec.unused_data:
        # decompress and yield the remainder
        yield dec.flush()

32 的偏移量向

zlib
标头发出信号,表明 gzip 标头是预期的但已被跳过。

S3 key 对象是一个迭代器,所以你可以这样做:

for data in stream_gzip_decompress(k):
    # do something with the decompressed data

10
投票

我必须做同样的事情,这就是我所做的:

import gzip
f = StringIO.StringIO()
k.get_file(f)
f.seek(0) #This is crucial
gzf = gzip.GzipFile(fileobj=f)
file_content = gzf.read()

6
投票

对于Python3x和boto3-

所以我使用 BytesIO 将压缩文件读入缓冲区对象,然后使用 zipfile 将解压流作为未压缩数据打开,并且我能够逐行获取数据。

import io
import zipfile
import boto3
import sys

s3 = boto3.resource('s3', 'us-east-1')


def stream_zip_file():
    count = 0
    obj = s3.Object(
        bucket_name='MonkeyBusiness',
        key='/Daily/Business/Banana/{current-date}/banana.zip'
    )
    buffer = io.BytesIO(obj.get()["Body"].read())
    print (buffer)
    z = zipfile.ZipFile(buffer)
    foo2 = z.open(z.infolist()[0])
    print(sys.getsizeof(foo2))
    line_counter = 0
    for _ in foo2:
        line_counter += 1
    print (line_counter)
    z.close()


if __name__ == '__main__':
    stream_zip_file()

0
投票

您可以尝试 PIPE 并读取内容,而无需下载文件

    import subprocess
    c = subprocess.Popen(['-c','zcat -c <gzip file name>'], shell=True, stdout=subprocess.PIPE,         stderr=subprocess.PIPE)
    for row in c.stdout:
      print row

此外“/dev/fd/”+ str(c.stdout.fileno()) 将为您提供可以传递给其他程序的 FIFO 文件名(命名管道)。


0
投票

我对 gzip 文件是这样做的:

import gzip
import boto3

s3 = boto3.resource('s3')
obj = s3.Object(bucket_name='Bucket', key='file.gz')
with gzip.GzipFile(fileobj=obj.get()["Body"]) as file:
    for line_bytes in file:
        print(line_bytes)
© www.soinside.com 2019 - 2024. All rights reserved.