Boto S3 API不会返回完整的键列表

时间:2014-07-08 14:19:53

标签: python amazon-web-services amazon-s3 boto

我在我的python脚本中使用boto S3 API,它慢慢地将数据从S3复制到我的本地文件系统。该脚本运行了好几天,但现在出现了问题。

我使用以下API函数来获取"目录"中的键列表:

keys = bucket.get_all_keys(prefix=dirname)

此功能(get_all_keys)并不总是返回完整的密钥列表,我的意思是我可以通过AWS网络界面或aws s3 ls s3://path看到更多密钥。

在版本2.15和2.30上重现了这个问题。

也许boto将我的一些请求缓存到S3(我一遍又一遍地重复相同的请求)? 如何解决这个问题,有什么建议吗?

4 个答案:

答案 0 :(得分:13)

有一种更简单的方法。 Bucket对象本身可以充当迭代器,它知道如何处理分页响应。因此,如果有更多可用结果,它将自动在后台获取它们。所以,这样的事情应该允许你迭代你桶中的所有对象:

for key in bucket:
    # do something with your key

如果你想指定一个前缀并获得以该前缀开头的所有键的列表,你可以这样做:

for key in bucket.list(prefix='foobar'):
    # do something with your key

或者,如果你真的想要建立一个对象列表,那么就这样做:

keys = [k for k in bucket]

但请注意,存储桶可以容纳无限数量的密钥,因此请小心,因为它会构建内存中所有密钥的列表。

答案 1 :(得分:5)

刚设法让它运转起来! 原来我在S3上的目录中有1013个密钥,由于AWS API的限制,get_all_keys只能返回1000个密钥。

解决方案很简单,只需使用更高级别的函数而不使用delimiter参数:

keys = list(bucket.list(prefix=dirname))

答案 2 :(得分:3)

您需要通过发出多个请求来对结果进行分页。 list()会自动为您执行此操作。您可以使用以下示例进行更好的控制或从失败的请求中恢复。

如果您正在使用数百万个对象,这种迭代方法也更具可扩展性。

marker = None
while True:
    keys = bucket.get_all_keys(marker=marker)
    last_key = None

    for k in keys:
        # TODO Do something with your keys!
        last_key = k.name

    if not keys.is_truncated:
        break

    marker = last_key

来自ResultSet docsget_all_keys() docs说这应该由for迭代器自动完成,但它没有。 :(

答案 3 :(得分:0)

在boto3中使用分页。这个功能应该给你答案:

def s3_list_files(bucket_name, prefix):
    paginator = client.get_paginator("list_objects")

    page_iterator = paginator.paginate(Bucket=bucket_name, Prefix=prefix)
    keys = []
    for page in page_iterator:
        if "Contents" in page:
            for key in page["Contents"]:
                keyString = key["Key"]
                keys.append(keyString)

    return keys if keys else []