有没有一种方法可以在亚马逊S3中touch()一个文件?

36

我目前正在使用Amazon S3,编写一款使用修改日期的程序。我正在寻找一种编辑修改日期的方法。

我可以遍历所有文件并按原样保存它们,但这听起来像是一个糟糕的解决方案。

在PHP中有这个函数touch()

是否有人知道解决方法或者有同样的问题?

6个回答

44

针对@Daniel Golden在@tkotisis回答中的评论,看起来AWS CLI工具至少不允许您将项目复制到其自身。但是,您可以通过更新元数据来“强制”复制。

$ aws s3 cp --metadata '{"touched":"now"}' s3://path/to/object s3://path/to/object

这将重新创建对象(将其下载到调用者并重新上传),替换其内容、所有者和元数据。这也会触发任何附加的Lambda事件。


7
这会导致一个错误:致命错误:调用HeadObject操作发生错误(404):键“index.html”不存在。 - Chad Johnson
如果启用了S3存储桶版本控制,这种方法将无法正常工作。它会创建一个重复的副本... - Jaeyoung Chun
如果目标是创建对象(而不仅仅是触摸现有对象),则此方法无效。 - Zhang18

18

您可以通过复制对象请求实现相同的功能,指定CopySource与目标键相同。

本质上,这将向S3发出PUT Object - COPY请求,其中包含相应的源和目标桶/键。


你知道这个代码具体是做什么的吗?它会为每个文件触发一个GET和PUT请求吗? - Ron van der Heijden
9
运行命令:s3cmd cp s3://path/to/file s3://path/to/file,其中两个路径相同,会出现以下错误:ERROR: S3 error: 400 (InvalidRequest): This copy request is illegal because it is trying to copy an object to itself without changing the object's metadata, storage class, website redirect location or encryption attributes. 错误表示:此复制请求是非法的,因为它试图将一个对象复制到自身,而不改变对象的元数据、存储类别、网站重定向位置或加密属性。 - Daniel Golden
虽然环境有所不同,但在luigi + python + spark中,您可以这样做: fs.put_string("", path) 其中fs是S3Client(可通过例如S3Target获得)。基本上,您可以将空字符串放入S3。 - pkopac
4
你是否像文档中所述一样,将请求头 x-amz-metadata-directive 设置为 REPLACE - tkotisis
4
这个可行 - 谢谢。aws s3 cp s3://path/to/file s3://path/to/file --metadata-directive REPLACE - Chirag Sejpal
显示剩余2条评论

6

这里有另一种上传空(或0字节)文件到S3的方法。我已验证其有效性。您也可以使用S3 API上传一个没有正文的文件,就像这样:

aws s3api put-object --bucket "myBucketName" --key "dir-1/my_null_file"

通常您需要指定一个--body blob,但这个选项只会像预期的那样添加密钥。在S3 API put-object上查看更多信息。

AWS CLI的版本为:aws-cli/2.0.4 Python/3.7.5 Windows/10 botocore/2.0.0dev8

以下是我在PHP中的操作方式(即使在过时的版本5.4中也可以运行,不过我得往回退):

// Init an S3Client
$awsConfig = $app->config('aws');
$aws       = Aws::factory($awsConfig);
$s3Bucket  = $app->config('S3_Bucket');
$s3Client  = $aws->get('s3');

// Set null/empty file.
$result = $s3Client->putObject([
    'Bucket' => $s3Bucket,
    'Key' => "dir-1/my_null_file",
    'Body' => '',
    'ServerSideEncryption' => 'AES256',
]);

1
终于有一个对我有效的答案了!谢谢! - akki
1
这实际上并没有回答标题问题。touch 不应更改文件的内容。它只应在文件存在时更新修改时间,而这将截断现有文件。 - Andrew Pickin
标记为不符合实际问题的要求。 - SamStephens

6

我经常在测试中使用“复制小技巧”,甚至我已经将一个方便的函数添加到我的.bashrc文件中:

s3-touch() {
  aws s3 cp \
    --metadata 'touched=touched' \
    --recursive --exclude="*" \
    --include="$2" \
    "${@:3}" \
    "$1" "$1"
}

示例用法:

# will do a dryrun on a copy operation
s3-touch s3://bucket/prefix/ "20200311*" --dryrun

# the real thing, creating events for all objects
# in s3://bucket/prefix/ that start with 20200311
s3-touch s3://bucket/prefix/ "20200311*"

我主要是为了触发S3事件而这样做的。


1

请查看https://github.com/emdgroup/awscli-s3touch

这是一个插件,可添加touch命令到AWS CLI中。

用法:

aws s3 touch my-bucket --prefix myfolder/

它通过读取附加到存储桶的事件并在客户端模拟这些事件来工作。


1
阅读源代码,该插件只是在发生PUT操作时触发应该被触发的事件,而不实际触及文件。仓库名称具有误导性。 - Ben Yitzhaki

1

在@g-io简化了我的一天后,这里提供了另一个版本的答案,使得触摸单个文件变得容易。

s3-touch-single() {
  aws s3 cp \
    --metadata 'touched=touched' \
    "${@:3}" \
    "$1" "$1"
}

例如,循环一个文件数组,我们需要touch它们:
paths=("mydir/image.png" "mydir2/image2.png")
for i in "${paths[@]}"; do s3-touch-single "s3://my-bucket/$i"; done

酷,有没有用Java API实现这个的方法? - peterk
问题:第四行应该写成"${@:2}"还是我错过了什么参数? - Stormcloud
1
@Stormcloud 老实说,我不记得为什么了,现在看脚本时确实看起来有些冗余。 - Ben Yitzhaki
@peterk 你可以以类似的方式使用Java SDK(只需使用Java而不是Bash)。它可能在后端同时使用相同的API。 - Ben Yitzhaki
@BenYitzhaki 有趣的是,我尝试过这样做,即更改元数据中的字段,然后使用新元数据将对象复制到自身。这确实会更改元数据,但在随后的访问中不会更改summary.getLastModified()值。 - peterk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接