使用boto

时间:2015-06-05 21:09:16

标签: python amazon-s3 gzip boto

我尝试使用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...

为什么会这样?我认为必须有一些我缺少的基本内容。

2 个答案:

答案 0 :(得分:10)

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

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

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 :(得分:0)

感谢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')