【问题标题】:How can I use versioning in S3 with boto3?如何在 S3 中通过 boto3 使用版本控制?
【发布时间】:2021-10-27 08:08:52
【问题描述】:

我正在使用带有 boto3 的版本化 S3 存储桶。如何检索给定密钥的所有版本(甚至所有密钥的所有版本)?我可以这样做:

for os in b.objects.filter(Prefix=pref):
    print("os.key")
     

但这只会给我每个键的最新版本。

【问题讨论】:

  • 问题的措辞是对象的版本,而不是版本 ID。虽然现有的两个答案给出了如何获取版本 ID,但它们没有显示如何获取版本。我添加了第三个答案,它显示了如何获取所有版本 ID,然后使用它们来获取对象的版本。

标签: python amazon-s3 boto3


【解决方案1】:
import boto3

bucket = 'bucket name'
key = 'key'
s3 = boto3.resource('s3')
versions = s3.Bucket(bucket).object_versions.filter(Prefix=key)

for version in versions:
    obj = version.get()
    print(obj.get('VersionId'), obj.get('ContentLength'), obj.get('LastModified'))

我有同样的问题,但我发现了这个here

【讨论】:

  • 太好了,谢谢!我不再从事这个项目了,但很高兴看到有一个解决方案。至于代码的解释,好吧。首先,您指定您之后的存储桶,然后指定密钥,它告诉 s3 您想要存储桶中的哪些对象。然后遍历所有版本,并打印 versionId 和长度。
  • 是的,例如,这实际上并没有说明如何使用 VersionId 获取对象,但大概可以通过这种方式过滤对象......
  • 我如何知道当前版本是什么?我的第一种方法是通过LastModified 订购,但也许最后一个版本被删除了?
  • aws s3api get-object --bucket BUCKETNAME --key KEY --version-id VERSION /path/to/filetosave.jpg
  • 小心,这也会返回以这个键开始的对象的版本,例如'key1'、'key2' 等。要排除这些,for 循环需要将它们过滤掉。
【解决方案2】:

boto3 s3 客户端有一个list_object_versions 方法。

resp = client.list_object_versions(Prefix=prefix, Bucket=bucket)

for obj in [*resp['Versions'], *resp.get('DeleteMarkers', [])]:
    print(f"Key: {obj['Key']}")
    print(f"VersionId: {obj['VersionId']}")
    print(f"LastModified: {obj['LastModified']}")
    print(f"IsLatest: {obj['IsLatest']}")
    print(f"Size: {obj.get('Size', 0)/1e6}")

假设您想删除除当前版本之外的所有内容,您可以通过将非 IsLatest 的对象添加到 to_delete 列表中来实现,然后运行以下命令:

for obj in to_delete:
    print(client.delete_object(Bucket=bucket, Key=obj['Key'], VersionId=obj['VersionId']))

【讨论】:

    【解决方案3】:

    现有答案描述了如何获取对象的版本 ID。我们有兴趣使用对象的版本,这通常涉及访问部分或全部对象。

    首先获取版本 ID。我将在这里使用al76 的答案获取版本ID 来说明boto3.resourceboto3.client 的示例。

    import boto3
    from collections import deque
    
    
    bucket = 'bucket name'
    key = 'key'
    s3 = boto3.resource('s3')
    versions = s3.Bucket(bucket).object_versions.filter(Prefix=key)
    s3_object_versions = deque()
    
    for version in versions:
        obj = version.get()
        s3_object_versions.appendleft(obj.get('VersionId'))
    

    接下来我们需要获取实际的版本化对象,有几种方法可以做到这一点,具体取决于您是否拥有 s3 资源或 s3 客户端。鉴于我们获得了资源的版本 ID,我们将从那里开始。

    # using the first version of the object
    obj_version = s3.ObjectVersion(bucket, key, s3_object_versions[0]).get()
    
    # if this object is really large this loop might execute for awhile
    for event in obj_version['Body']:
        print(event)
    

    请注意,每个 event 都是一个 botocore.response.StreamingBody 对象,如果您的对象是 csv 文件(等),则可能不对应一行。

    现在作为一种替代方法,您可能有一个 s3 客户端,而不是一个 s3 资源对象。在 s3 资源中,您可以通过.meta 访问客户端。这是代码:

    response = s3.meta.client.get_object(Bucket=bucket, Key=key, VersionId=s3_object_versions[-1])
    
    # same caveat as above, for loop may run for awhile if object is large
    for event in response['Body']:
        print(event)
    

    第三个选项与第一个非常相似,直接使用资源、存储桶和对象。

    object = s3.Bucket(bucket).Object(key).get()
    object_version = object.Version(s3_object_versions[0]).get()
    #  again careful if object is large-will run awhile and fill stdout
    for event in object_version['Body']:
        print(event)
    

    第四个选项——同样使用 s3 客户端是直接下载文件。

    object_original_version = s3.meta.client.download_file(bucket, key, '/tmp/' + key, ExtraArgs={'VersionId': s3_object_versions[0]})
    

    然后您可以通过open() 调用或更专业的文件格式从/tmp 读取文件。

    在您的代码中,您可能希望用try/except 等包装这些以处理错误,除非这是原型设计/实验工作。

    【讨论】:

    • 超级。谢谢卢卡斯。
    猜你喜欢
    • 2012-09-16
    • 1970-01-01
    • 1970-01-01
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-17
    • 2019-05-13
    相关资源
    最近更新 更多