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

y53ybaqx  于 2023-04-28  发布在  Java
关注(0)|答案(8)|浏览(156)

我需要更新所有AmazonS3云文件中该高速缓存控制头。但是,我不知道如何使用jclouds API来实现这一点。我使用的是Apache Jclouds插件。我得到了两个相关的答案:

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

mcdcgff0

mcdcgff01#

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

这是否是一个哲学上的“更新”是由你来决定。

lhcgjxsq

lhcgjxsq2#

您不能:
每个Amazon S3对象都有数据、密钥和元数据。对象键(或键名)唯一标识存储桶中的对象。对象元数据是一组名称-值对。您可以在上载对象元数据时对其进行设置。上传对象后,无法修改对象元数据。修改对象元数据的唯一方法是创建对象的副本并设置元数据。
http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html

vhmi4jdf

vhmi4jdf3#

PHP示例

我知道这个问题不是PHP特定的,但它可能会帮助某人,因为它是谷歌的顶级结果。
此操作将覆盖现有对象。

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

roejwanj

roejwanj4#

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

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

uurv41yg5#

我最近不得不这样做,并使用JS:

const {
  S3Client,
  ListObjectsCommand,
  HeadObjectCommand,
  CopyObjectCommand,
} = require('@aws-sdk/client-s3');
const fs = require('fs');

const client = new S3Client({
  region: 'us-west-2',
});

const files = fs.readFileSync('images.txt', 'utf8').split('\n');

async function run() {
  for (const prefix of files) {
    await fixMetdata(prefix);
  }
}

const BUCKET_NAME = 'my-bucket';

async function fixMetdata(prefix) {
  // console.error(prefix);
  try {
    const listObjects = new ListObjectsCommand({
      Bucket: BUCKET_NAME,
      Prefix: prefix,
      MaxKeys: 1,
    });
    const data = await client.send(listObjects);

    if (!data.Contents) return;

    data.Contents.filter((f) => f.Key.includes('.jpg')).forEach(
      async (file) => {
        const fileMetadata = await client.send(
          new HeadObjectCommand({ Bucket: BUCKET_NAME, Key: file.Key })
        );
        // console.error(fileMetadata.ContentType);
        if (fileMetadata.ContentType !== 'image/jpeg') {
          const updatedMetadata = await client.send(
            new CopyObjectCommand({
              Bucket: BUCKET_NAME,
              Key: file.Key,
              CopySource: `${BUCKET_NAME}/${file.Key}`,
              MetadataDirective: 'REPLACE',
              ContentType: 'image/jpeg',
            })
          );
          console.log(file.Key);
        }
      }
    );
  } catch (err) {
    console.error('Error', err);
  }
}

run();
izj3ouym

izj3ouym6#

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

oo7oh9g9

oo7oh9g97#

我在任何地方都找不到它的文档,但是如果你使用Step Functions to make an SDK call to S3,你可以像上面的PHP和Ruby一样使用MetadataDirective来设置元数据(这个例子显示了s3:copyObject的参数):

{
  "Bucket.$": "$.bucketName",
  "CopySource.$": "$.bucketSourceLocation",
  "Key.$": "$.destinationKey",
  "Acl": "bucket-owner-full-control",
  "ServerSideEncryption": "AES256",
  "MetadataDirective": "REPLACE",
  "Metadata": {
    "my-metadata.$": "$.my-metadata"
  }
}
xmd2e60i

xmd2e60i8#

截至2018年3月,AWS SDK的最新版本。NET Core已更改。它现在使用异步编程。许多方法签名已更改。虽然如果没有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);

相关问题