如何更新现有 Amazon S3 文件的元数据?

How do I update metadata for an existing Amazon S3 file?

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

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

你不能:

Each Amazon S3 object has data, a key, and metadata. Object key (or key name) uniquely identifies the object in a bucket. Object metadata is a set of name-value pairs. You can set object metadata at the time you upload it. After you upload the object, you cannot modify object metadata. The only way to modify object metadata is to make a copy of the object and set the metadata.

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

可以通过执行对象复制来更改元数据(参见 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);

这是否是哲学上的 "update" 由您决定。

截至 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);

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
    ]
]);

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

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

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"
})