背景
正常来说,如果你想从 AWS S3 bucket 里读取某个特定 key 所对应的对象,比如某个图片文件,那么事情就很简单了。
但如果你需要在 bucket 里找到一个满足特定要求的对象,事情就变得麻烦起来了。最近我就遇到了这样一个问题,需要列出 S3 bucket 当前目录中内容,基于一些判断再进行下一步操作。
这个问题听起来很简单,上网搜了一下,在这个 AWS 官网链接 中找到了列出 bucket 内容的方法。
但意料之外的是,用示例中的方法会把全部符合条件的对象都列出来,而不只是当前目录中的对象。虽然这样也获取到了所需信息,但效率很低,很不方便。如果 bucket 中对象数量庞大,这样肯定是行不通的。
AWS S3 bucket 中没有“目录”的概念
于是我又搜了一下,发现AWS S3 bucket 中其实并没有“目录”的概念。顾名思义,bucket 应该是一种“键-值”存储形式,和以层层目录嵌套为特征的文件系统是完全不同的。
比如,如果你有一个对象,其 key 为:
folder1/folder2/object.json
那么这并不是一个嵌套在两层文件夹结构中的 object.json
文件,而更像是一个名字里有两个 /
的文件。
然而你在 S3 控制台浏览 bucket 内容的时候,明明是在按照文件系统的方式访问的啊!比如上面那个文件,的确是在依次进入 folder1
和 folder2
之后才能看到 object.json
。但这种目录层次实际上也是 S3 控制台 GUI 虚拟出来的,实际上并不存在。
Java 中如何列出当前“目录”中的对象 key
好吧,虽然 S3 bucket 中其实没有“目录”的概念,但既然大家都习惯于按照文件系统的方式来看待这些对象,那总该有办法能按照文件系统的方式,把当前“目录”中的内容列出来吧!
的确是有办法的,不过相当反直觉。假设你的 bucket 结构如下:
mybucket
folder1
object1.json
object2.json
folder2
object3.json
object4.json
folder3
object5.json
object6.json
如果想要列出 folder1
中的内容,那么应该将 prefix
设置为 folder1
,将 delimiter
设置为 /
,类似于下面这样:
AmazonS3 s3 = AmazonS3ClientBuilder
.standard()
.withRegion(region)
.build();
ListObjectsV2Request request = new ListObjectsV2Request()
.withBucketName(bucketName)
.withPrefix("folder1")
.withDelimiter("/");
ListObjectsV2Result result = s3.listObjectsV2(request);
这样一来,result.getObjectSummaries()
会返回 folder1
中的对象(不包括目录):
folder1/object1.json
folder1/object2.json
而 result.getCommonPrefixes()
则返回 folder1
中的 “目录”:
folder1/folder2
folder1/folder3
参考连接
Listing object keys programmatically
How can I get only one level of objects in a S3 bucket?