我在我的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(我一遍又一遍地重复相同的请求)? 如何解决这个问题,有什么建议吗?
答案 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 docs的get_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 []