【问题标题】:How do I update metadata for an existing Amazon S3 file?如何更新现有 Amazon S3 文件的元数据?
【发布时间】:2015-12-15 06:51:42
【问题描述】:

我需要更新所有 AmazonS3 的云文件中的缓存控制标头。但是,我不知道如何使用 jclouds API 做到这一点。 我正在使用 apache jclouds 插件。我得到了两个相关的答案:

第一个答案是建议使用 SwiftKey Api 类,该类在 grails 的 jcloud 插件中不可用。第二个答案是使用 AWS java sdk,它已经有一个 grails 包装插件https://grails.org/plugin/aws-sdk,但它不支持元数据更新。

【问题讨论】:

    标签: java grails amazon-web-services amazon-s3 jclouds


    【解决方案1】:

    可以通过执行对象复制来更改元数据(请参阅How to update metadata using Amazon S3 SDK):

    ObjectMetadata metadataCopy = new ObjectMetadata();
    // copy previous metadata
    metadataCopy.addUserMetadata("newmetadata", "newmetadatavalue");
    
    CopyObjectRequest request = new CopyObjectRequest(bucketName, existingKey, bucketName, existingKey)
          .withNewObjectMetadata(metadataCopy);
    
    amazonS3Client.copyObject(request);
    

    这是否是哲学上的“更新”由您决定。

    【讨论】:

    • 谢谢丹,我最终做了同样的事情。
    【解决方案2】:

    你不能:

    每个 Amazon S3 对象都有数据、键和元数据。对象键(或 key name) 唯一标识存储桶中的对象。对象元数据 是一组名称-值对。您可以在当时设置对象元数据 你上传它。 上传对象后,无法修改对象 元数据。修改对象元数据的唯一方法是复制 对象并设置元数据。

    http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html

    【讨论】:

    • 我发现有关元数据主题的 AWS 文档非常令人困惑 - 除了您提供的链接之外,我还找到了他们的用户指南的另一个链接,其中显示了如何使用管理控制台。我能想出的解决这个冲突的唯一方法是,当他们说“你不能修改对象元数据”时,他们的意思是,你不能修改特定元数据键的值。你的想法是什么? docs.aws.amazon.com/AmazonS3/latest/UG/…
    • 也许他们的意思是你不能通过 REST 接口修改元数据,但你可以通过管理控制台? (在幕后它可能会克隆和删除)。
    • 请参阅下面的解决方案,您可以更新现有的 S3 对象并同时设置新的/更新的元数据。类似于复制方案。
    • 我意识到这是一个旧线程,但"Editing object metadata in the Amazon S3 console" 上的文档现在清楚地指出“此操作创建具有更新设置和最后修改日期的对象的副本。”所以对 web 控制台没有特殊处理。
    【解决方案3】:

    PHP 示例

    我知道这个问题不是特定于 PHP 的,但它可能对某人有所帮助,因为它是 Google 上的最高结果。

    这将覆盖现有对象。

    $client = new \Aws\S3\S3Client([
        'version' => '2006-03-01',
        'region' => 'BUCKET-REGION'
    ]);
    
    $updateResponse = $client->copyObject([
        'Key' => 'OBJECTKEY',
        'Bucket' =>  'MYBUCKET',
        'CopySource' => 'MYBUCKET/OBJECTKEY',
        'MetadataDirective' => 'REPLACE',
        'Metadata' => [
            'width' => 441,
            'height' => 189
        ]
    ]);
    

    【讨论】:

    • 您能帮我更新 laravel PHP 中现有对象的元数据吗?我已经尝试过您的解决方案,但无法更新现有文件的元数据。谢谢
    【解决方案4】:

    如其他答案所述,可以发出“复制”请求,覆盖现有记录。

    Ruby 示例

    s3_client.copy_object({
      bucket: BUCKET, # Destination
      key: KEY, # Destination
      copy_source: "/#{BUCKET}/#{KEY}", # Source
      content_type: "text/html; charset=utf8", # Metadata update
      metadata_directive: "REPLACE"
    })
    

    【讨论】:

    • 谢谢。旁注:有趣的是,在 java/ruby 世界中,这个老问题仍然是相关的! OP 使用 javascript 框架,即使是 2 年前的问题也变得无关紧要。
    • @PriyanshuChauhan 它显示了 JS 世界是多么不成熟;)
    【解决方案5】:

    就我而言,我关心对象版本,复制会创建一个新版本。我决定使用可变元数据创建一个并行的“隐藏”对象。例如,如果我有/foo/bar/baz,那么我将创建/foo/bar/.baz。

    【讨论】:

    • 那么对于您上传到 AWS S3 的每个文件,您都上传了第二个嵌入了 MD5 的隐藏文件?这不会增加 PUT 和 GET 的成本吗?
    • 可以,但我的应用程序容量不高。
    【解决方案6】:

    截至 2018 年 3 月,适用于 .NET Core 的 AWS 开发工具包的最新版本已更改。它现在使用异步编程。许多方法签名已更改。如果没有 Dan 建议的对象复制解决方案,您仍然无法更改元数据,但这样做的代码已经有了。

    我的解决方案是使用修改后的元数据更新现有的 S3 对象。

    以下内容适用于我更新单个元数据值(基于键和新值)。我有两个用于设置元数据的循环,但可以优化为只有一个:

    string fileContents = string.Empty;
    Dictionary<string, string> fileMetaData = null;
    
    GetObjectRequest request = new GetObjectRequest
    {
      BucketName = bucketName,
      Key = setKeyName
    };
    
    var response = await s3Client.GetObjectAsync(request);
    
    // Read the contents of the file
    using (var stream = response.ResponseStream)
    {
      // Get file contents
      TextReader tr = new StreamReader(stream);
      fileContents = tr.ReadToEnd();
    }
    
    // Create the File Metadata collection
    fileMetaData = new Dictionary<string, string>();
    foreach (string metadataKey in response.Metadata.Keys)
    {
      fileMetaData.Add(metadataKey, response.Metadata[metadataKey]);
    }
    
    // Update the metadata value (key to update, new value)
    fileMetaData[metaDataKeyToUpdate] = metaDataNewValue;
    
    // Update the existing S3 object    
    PutObjectRequest putRequest1 = new PutObjectRequest
    {
      BucketName = bucketName,
      Key = setKeyName,
      ContentBody = fileContents
    };
    
    // Set the metadata
    foreach (string metadataKey in response.Metadata.Keys)
    {
      putRequest1.Metadata.Add(metadataKey, fileMetaData[metadataKey]);
    }
    
    PutObjectResponse response1 = await s3Client.PutObjectAsync(putRequest1);
    

    【讨论】:

    • 将整个文件下载到客户端的内存中,因此仅适用于非常有限的用例。
    • 是的,你是对的。罪有应得! PST:对象复制真是太讨厌了 :)
    猜你喜欢
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 2017-07-16
    • 2021-03-09
    • 2017-03-24
    • 2011-06-12
    • 2019-05-03
    • 2021-09-26
    相关资源
    最近更新 更多