Boto S3 API未返回完整的键列表
我在我的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 个回答
在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 []
你需要通过多次请求来分页获取结果。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 文档的信息显示,get_all_keys() 文档提到这个应该由 for 循环自动完成,但实际上并不是这样。 :(
我终于让它工作了!
原来我在S3的目录里有1013个文件,而get_all_keys
这个函数由于AWS的限制,只能返回1000个文件。
解决办法很简单,只需要使用一个更高级的函数,不要加delimiter
这个参数就行:
keys = list(bucket.list(prefix=dirname))
其实有个更简单的方法。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]
不过要注意,桶可以存放无限数量的键,所以在使用的时候要小心,因为这样会把所有的键都放到内存里。