Boto3 S3,按最后修改排序桶

nat*_*ate 15 python amazon-s3 amazon-web-services python-3.x boto3

我需要使用Boto3从S3获取项目列表,但不是返回默认排序顺序(降序),而是希望它通过反向顺序返回它.

我知道你可以通过awscli来做到这一点:

aws s3api list-objects --bucket mybucketfoo --query "reverse(sort_by(Contents,&LastModified))"
Run Code Online (Sandbox Code Playgroud)

并通过UI控制台实现(不确定这是完成客户端还是服务器端)

我似乎无法在Boto3中看到如何做到这一点.

我目前正在获取所有文件,然后排序......但这似乎有点过头了,特别是如果我只关心10个左右的最新文件.

过滤系统似乎只接受s3的前缀,没有别的.

hel*_*loV 17

如果存储桶中没有多个对象,则可以使用Python根据需要对其进行排序.

定义lambda以获取最后修改时间:

get_last_modified = lambda obj: int(obj['LastModified'].strftime('%s'))
Run Code Online (Sandbox Code Playgroud)

获取所有对象并按上次修改时间对其进行排序.

s3 = boto3.client('s3')
objs = s3.list_objects_v2(Bucket='my_bucket')['Contents']
[obj['Key'] for obj in sorted(objs, key=get_last_modified)]
Run Code Online (Sandbox Code Playgroud)

如果要反转排序:

[obj['Key'] for obj in sorted(objs, key=get_last_modified, reverse=True)]
Run Code Online (Sandbox Code Playgroud)

  • list_objects_v2最多返回1000个对象,如果您的存储桶包含超过1000个,则上述操作将无效 (4认同)
  • @Tomer这就是我放弃免责声明的原因`如果桶里没有多少物品 (3认同)
  • 显然使用“%s”是不受欢迎的。您可以使用“.timestamp()”代替:/sf/ask/822011361/ (3认同)

小智 11

上面的轻微改进:

import boto3

s3 = boto3.resource('s3')
my_bucket = s3.Bucket('myBucket')
files = my_bucket.objects.filter()
files = [obj.key for obj in sorted(files, key=lambda x: x.last_modified, 
    reverse=True)]
Run Code Online (Sandbox Code Playgroud)


ArK*_*Kan 7

现在可以使用 JMESPath 搜索存储桶,就像我们在 AWS CLI 中执行的操作一样(示例)。

import boto3
s3 = boto3.client("s3")

s3_paginator = s3.get_paginator('list_objects_v2')
s3_iterator = s3_paginator.paginate(Bucket='your-bucket-name')

filtered_iterator = s3_iterator.search(
    "Contents[?starts_with(Key, 'folder6/')]"
    " | reverse(sort_by(@, &to_string(LastModified)))"
    " | @[].Key"
    " | [:2]"
)

for key_data in filtered_iterator:
    print(key_data)
Run Code Online (Sandbox Code Playgroud)

JMES路径解释

  1. Contents[?starts_with(Key, 'folder6/')]:可选,选择特定文件夹内的对象。
  2. reverse(sort_by(@, &to_string(LastModified))):按“LastModified”日期值降序对对象进行排序。
  3. @[].Key:获取对象名称。
  4. [:2]: 获得前 2 个。

例如,如果存储桶数据如下所示:

{
  "Contents": [
    {"Key": "folder6/file-64.pdf", "LastModified": "2014-11-21T19:04:05.000Z", "ETag": "\"70ee1738b6b21e2c8a43f3a5ab0eee64\"", "Size": 187932, "StorageClass": "STANDARD"},
    {"Key": "folder5/file-63.pdf", "LastModified": "2014-11-21T19:03:05.000Z", "ETag": "\"70ee1738b6b21e2c8a43f3a5ab0eee63\"", "Size": 227543, "StorageClass": "STANDARD"},
    {"Key": "folder6/file-62.pdf", "LastModified": "2014-11-21T19:02:05.000Z", "ETag": "\"70ee1738b6b21e2c8a43f3a5ab0eee62\"", "Size": 173484, "StorageClass": "STANDARD"},
    {"Key": "folder6/file-61.pdf", "LastModified": "2014-11-21T19:01:05.000Z", "ETag": "\"70ee1738b6b21e2c8a43f3a5ab0eee61\"", "Size": 192940, "StorageClass": "STANDARD"}
  ]
}
Run Code Online (Sandbox Code Playgroud)

它将产生这样的结果::

[
  "folder6/file-64.pdf",
  "folder6/file-62.pdf"
]
Run Code Online (Sandbox Code Playgroud)

  • 这会在客户端进行排序,因此您无论如何都会下载所有数据,并且它比使用 Python 方法执行排序要慢。 (3认同)

小智 6

似乎无法通过使用 boto3 进行排序。根据文档,boto3 只支持集合的这些方法:

all(), filter(**kwargs), page_size(**kwargs), limit(**kwargs)

希望这在某种程度上有所帮助。 https://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.ServiceResource.buckets


nat*_*ate 6

我对@helloV在下面发布的内容做了一些变化.它不是100%最优,但它完成了boto3到目前为止的限制.

s3 = boto3.resource('s3')
my_bucket = s3.Bucket('myBucket')
unsorted = []
for file in my_bucket.objects.filter():
   unsorted.append(file)

files = [obj.key for obj in sorted(unsorted, key=get_last_modified, 
    reverse=True)][0:9]
Run Code Online (Sandbox Code Playgroud)

  • 警告:虽然您想要获取最后 X 个对象,但在此解决方案中,您仍将对存储桶中的所有对象执行 GET,这可能会导致大量成本(特别是如果您每次都运行此操作)。 (3认同)