这里是 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
的子对象。 .
我需要完成几件事:
- 我需要一个字符串数组/映射/数据结构(Java
Array<String>
或 ScalaArray[String]
),其中包含 ID 目录的所有字母数字 ID(因此元素 0 是"3dj439fj9fj49j"
,元素 1 是"3eidi04d40d40d"
,等等.);和 - 我需要一个日期数组/映射/数据结构(Java
Array<Date>
或 ScalaArray[Date]
),其中包含每个 ID 目录对应的data.json
的上次修改时间戳文件。所以如果mybucket/3dj439fj9fj49j/data.json
上次修改日期/时间戳为 2017-05-29 11:19:24T,那么该日期时间将是第二个数组的第一个元素 - 这两个数组/映射/数据结构需要关联,这意味着我可以访问第一个 (ID) 数组的第 4 个元素并获取
my-bucket
下面的第 5 个 ID 目录,我还可以访问第二个(日期)数组的第 4 个元素并获取第 5 个 ID 目录的data.json
的上次修改时间戳子对象
这些不一定必须是数组,它们可以是映射、元组等。如上所述,我只需要 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 专家可以发现我哪里出错了,或者可以在此处将我推向正确的方向吗?提前致谢!
最佳答案
您可以调用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)
解释
首先,我们有一些 Bootstrap 来设置凭据和创建客户端。然后,我们发出 listObjects
,这会触发对 S3 服务的调用。我们将这些结果过滤
为仅以“data.json”结尾的键。然后,我们将结果映射
到由父路径名和对象的最后修改日期/时间组成的元组。为了确定父路径,我们在路径分隔符上split
并检索先前的路径组件。作为一种特殊情况,如果文件位于根目录中,则我们称其父级为 "/"
。
我选择将结果表示为元组,但如果您愿意,可以将其更改为其他数据结构。
请注意,对于包含大量对象的存储桶,您可能需要使用 AmazonS3#listObjects(String, String)
相反,这样您就可以将返回的结果限制为与特定前缀匹配的键。这将减少响应消耗的网络带宽量和响应数据所需的处理量。
要获得更多选项,您还可以考虑 AmazonS3#listObjects(ListObjectsRequest)
或 AmazonS3#listObjectsV2(ListObjectsV2Request)
.
关于scala - 使用 AWS S3 Java 客户端获取目录和对象元数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45444653/