【问题标题】:Using AWS S3 Java client to obtain directory and object metadata使用 AWS S3 Java 客户端获取目录和对象元数据
【发布时间】:2017-08-03 05:39:24
【问题描述】:

这里是Scala 2.11,虽然这涉及AWS S3 Java client API,所以这确实是一个Java 问题。如果有人可以在 Scala 中提供答案,那将是真棒,但我会很高兴接受任何有效的 Java 答案(我总是可以在自己的时间对其进行 Scala 化)。


我正在尝试使用 AWS S3 客户端库连接到 S3 上的存储桶,该存储桶是它下面的以下目录结构:

my-bucket/
    3dj439fj9fj49j/
        data.json
    3eidi04d40d40d/
        data.json
    a874739sjsww93/
        data.json
    ...

因此,存储桶下的每个直接子对象都是一个带有字母数字名称的目录。我将这些称为“ID 目录”。这些 ID 目录中的每一个都有一个名为data.json 的all 子对象。

我需要完成几件事:

  1. 我需要一个包含 ID 目录的所有字母数字 ID 的字符串数组/映射/数据结构(Java Array<String> 或 Scala Array[String])(因此元素 0 是 "3dj439fj9fj49j",元素 1 是 "3eidi04d40d40d",等等.);和
  2. 我需要一个日期数组/映射/数据结构(Java Array<Date> 或 Scala Array[Date]),其中包含每个 ID 目录对应的 data.json 文件的上次修改时间 时间戳。因此,如果 mybucket/3dj439fj9fj49j/data.json 的上次修改日期/时间戳为 2017-05-29 11:19:24T,那么该日期时间将是第二个数组的第一个元素
  3. 这两个数组/映射/数据结构需要是关联的,这意味着我可以访问,比如说,第一个 (ID) 数组的第 4 个元素,并获得my-bucket 下的第 5 个 ID 目录,我还可以访问第 4 个第二个(日期)数组的元素并获取第 5 个 ID 目录的 data.json 子对象的 Last Modified 时间戳

这些不一定必须是数组,它们可以是映射、元组等。如上所述,我只需要 1+ 个数据结构来保存此内容。

在lib's Javadocs 中,我看到了一个ObjectMetadata#getLastModified 字段,但我没有看到任何用于读取给定S3Object 的父目录路径(即data.json 的父ID 目录)的任何内容。总而言之,我的最佳尝试非常失败:

val s3Client = new AmazonS3Client(new BasicAWSCredentials(accessKey, secretKey))
val bucketRoot : S3Object = s3Client.getObject("myBucket","/")

// TODO: How to query 'bucketRoot' for all its child ID directories?
val idDirs : Array[S3Object] = ???

var dataMap : Map[String,Date] = null
idDirs.foreach(idDir ->
  // TODO: getName() and getChildSomehow() don't exist...obviously
  dataMap :+ idDir.getName() -> idDir.getChildSomehow("data.json").getObjectMetadata.getLastModified
)

任何 S3 API 专家都可以发现我哪里出错了,或者在此处将我推向正确的方向?提前致谢!

【问题讨论】:

标签: scala amazon-s3 java-client


【解决方案1】:

您可以调用AmazonS3#listObjects(String) 获取存储桶中的对象列表。对于找到的每个密钥,响应将包含一个 S3ObjectSummary。您可以致电S3ObjectSummary#getLastModified() 获取上次修改的日期/时间。

这是一个将所有内容与一些 Scala 代码联系在一起的示例。

来自 S3 存储桶的输入

> aws s3 ls --recursive s3://<REDACTED>/
2017-08-02 13:45:12          0 3dj439fj9fj49j/
2017-08-02 13:45:28          0 3dj439fj9fj49j/data.json
2017-08-02 13:45:16          0 3eidi04d40d40d/
2017-08-02 13:45:33          0 3eidi04d40d40d/data.json
2017-08-02 13:45:19          0 a874739sjsww93/
2017-08-02 13:45:37          0 a874739sjsww93/data.json

代码

import collection.JavaConverters._

import com.amazonaws.auth.AWSStaticCredentialsProvider
import com.amazonaws.auth.BasicAWSCredentials
import com.amazonaws.regions.Regions
import com.amazonaws.services.s3.AmazonS3ClientBuilder

val key = <REDACTED>
val secret = <REDACTED>
val bucketName = <REDACTED>
val region = <REDACTED>

val creds = new BasicAWSCredentials(key, secret)
val s3 = AmazonS3ClientBuilder.standard.withCredentials(new AWSStaticCredentialsProvider(creds)).withRegion(region).build

val objectSummaries = s3.listObjects(bucketName).getObjectSummaries.asScala
val dataFiles = objectSummaries.filter { _.getKey.endsWith("data.json") }
val dataDirectories = dataFiles.map(dataFile => {
  val keyComponents = dataFile.getKey.split("/")
  val parent = if (keyComponents.length > 1) keyComponents(keyComponents.length - 2) else "/"
  (parent, dataFile.getLastModified)
})
dataDirectories.foreach(println)

输出

(3dj439fj9fj49j,Wed Aug 02 13:45:28 PDT 2017)
(3eidi04d40d40d,Wed Aug 02 13:45:33 PDT 2017)
(a874739sjsww93,Wed Aug 02 13:45:37 PDT 2017)

说明

首先,我们有一些引导程序来设置凭据并创建客户端。然后,我们发出listObjects,它会触发对 S3 服务的调用。我们filter 这些结果只包含以“data.json”结尾的键。然后,我们map 将结果转换为由父路径名和对象的最后修改日期/时间组成的元组。为了确定父路径,我们在路径分隔符上split 并检索前一个路径组件。作为一种特殊情况,如果文件在根目录中,那么我们说它的父级是"/"。

我选择将结果表示为元组,但如果您愿意,可以将其更改为其他数据结构。

请注意,对于包含大量对象的存储桶,您可能希望改用AmazonS3#listObjects(String, String),以便您可以将返回的结果限制为与特定前缀匹配的键。这将减少响应所消耗的网络带宽量以及响应数据所需的处理量。

如需更多选择,您还可以考虑AmazonS3#listObjects(ListObjectsRequest) 或AmazonS3#listObjectsV2(ListObjectsV2Request)。

【讨论】:

    猜你喜欢
    • 2018-11-26
    • 1970-01-01
    • 1970-01-01
    • 2023-02-24
    • 1970-01-01
    • 2017-10-24
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多