【问题标题】:Infinite loop when streaming a .gz file from S3 using boto使用 boto 从 S3 流式传输 .gz 文件时的无限循环
【发布时间】:2015-08-20 22:55:04
【问题描述】:

我正在尝试使用 boto 从 S3 流式传输 .gz 文件并遍历解压缩文本文件的行。神秘的是,循环永远不会终止。当整个文件被读取后,迭代从文件的开头重新开始。

假设我创建并上传了一个输入文件,如下所示:

> echo '{"key": "value"}' > foo.json
> gzip -9 foo.json
> aws s3 cp foo.json.gz s3://my-bucket/my-location/

然后我运行以下 Python 脚本:

import boto
import gzip

connection = boto.connect_s3()
bucket = connection.get_bucket('my-bucket')
key = bucket.get_key('my-location/foo.json.gz')
gz_file = gzip.GzipFile(fileobj=key, mode='rb')
for line in gz_file:
    print(line)

结果是:

b'{"key": "value"}\n'
b'{"key": "value"}\n'
b'{"key": "value"}\n'
...forever...

为什么会这样?我想一定有一些非常基本的东西我错过了。

【问题讨论】:

    标签: python amazon-s3 gzip boto


    【解决方案1】:

    啊,博托。问题是如果在密钥被完全读取一次后调用 read 方法会重新下载密钥(比较 read 和 next 方法以查看差异)。

    这不是最干净的方法,但它解决了问题:

    import boto
    import gzip
    
    class ReadOnce(object):
        def __init__(self, k):
            self.key = k
            self.has_read_once = False
    
       def read(self, size=0):
           if self.has_read_once:
               return b''
           data = self.key.read(size)
           if not data:
               self.has_read_once = True
           return data
    
    connection = boto.connect_s3()
    bucket = connection.get_bucket('my-bucket')
    key = ReadOnce(bucket.get_key('my-location/foo.json.gz'))
    gz_file = gzip.GzipFile(fileobj=key, mode='rb')
    for line in gz_file:
        print(line)
    

    【讨论】:

    • +1:这太棒了。事实上,使用您的包装器,我可以直接从压缩的 S3 对象中读取 pandas DataFrame。谢谢!
    • 不错!这同样适用于 CSV 下载,对我来说,它也表现出奇怪的行为,例如文件结尾与开头连接。很想知道为什么 boto 会这样做 - 非常大的问题 IMO
    • 另外值得注意的是,当将此解决方案作为上下文管理器运行时,我还需要实现 close 函数。它只是将close 委托给self.key.close()
    • 我们可以将此解决方案扩展到boto3 以读取 10 MiB 块中的 zip 文件吗?
    【解决方案2】:

    感谢zweiterlinde 的精彩见解和excellent answer provided

    我正在寻找一种将压缩的 S3 对象直接读入 Pandas DataFrame 的解决方案,并使用他的包装器,可以用两行表示:

    with gzip.GzipFile(fileobj=ReadOnce(bucket.get_key('my/obj.tsv.gz')), mode='rb') as f:
        df = pd.read_csv(f, sep='\t')
    

    【讨论】:

    • Python 不是关于“谁能用最少的行数得到it”,去读圣经-> python -m this
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-17
    相关资源
    最近更新 更多