2014-07-08 61 views
6

我在我的Python脚本中使用boto S3 API,它将S3中的数据缓慢地复制到本地文件系统。这个脚本运行了好几天,但现在有一个问题。Boto S3 API不返回完整的密钥列表

我用下面的API函数来获取在“目录”项的列表:

keys = bucket.get_all_keys(prefix=dirname) 

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

在版本2.15和2.30上转载了此问题。

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

回答

12

还有一个更简单的方法。 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] 

但是请注意,这桶能装钥匙的数量不受限制,从而保重l,因为它会构建内存中所有密钥的列表。

+0

如何列出特别前缀键 –

+1

刚刚更新用一个例子答案。 – garnaat

5

只是设法让它工作! 事实证明,我在S3上的目录中有1013个密钥,get_all_keys由于AWS API限制只能返回1000个密钥。

解决方法很简单,只需使用更多的高级功能,而不delimiter参数:

keys = list(bucket.list(prefix=dirname)) 
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 docs说,这应该autoamtically通过对迭代器来完成,但事实并非如此。 。:(在boto3

1

使用分页这个功能应该给你答案:

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 [] 
相关问题