我使用下面提到的代码来获取s3存储桶中所有文件名的列表。 s3中有两个桶。对于下面的一个桶代码返回所有文件名(超过1000),但相同的代码仅返回另一个桶的1000个文件名。我只是不知道发生了什么。 为什么相同的代码运行一个桶而不是其他的?
我的存储桶也有层次结构文件夹/ filename.jpg。
ObjectListing objects = s3.listObjects("bucket.new.test");
do {
for (S3ObjectSummary objectSummary : objects.getObjectSummaries()) {
String key = objectSummary.getKey();
System.out.println(key);
}
objects = s3.listNextBatchOfObjects(objects);
} while (objects.isTruncated());
答案 0 :(得分:9)
改善@ Abhishek自己的答案。 此代码略短。还修复了变量名称。
List<S3ObjectSummary> keyList = new ArrayList<S3ObjectSummary>();
ObjectListing objects = s3.listObjects("bucket.new.test");
keyList.addAll(objects.getObjectSummaries());
while (objects.isTruncated()) {
objects = s3.listNextBatchOfObjects(objects);
keyList.addAll(objects.getObjectSummaries());
}
答案 1 :(得分:7)
对于Scala开发人员,这里使用官方AWS SDK for Java执行 完整扫描并映射 的AmazonS3存储桶内容的递归功能
import com.amazonaws.services.s3.AmazonS3Client
import com.amazonaws.services.s3.model.{S3ObjectSummary, ObjectListing, GetObjectRequest}
import scala.collection.JavaConversions.{collectionAsScalaIterable => asScala}
def map[T](s3: AmazonS3Client, bucket: String, prefix: String)(f: (S3ObjectSummary) => T) = {
def scan(acc:List[T], listing:ObjectListing): List[T] = {
val summaries = asScala[S3ObjectSummary](listing.getObjectSummaries())
val mapped = (for (summary <- summaries) yield f(summary)).toList
if (!listing.isTruncated) mapped.toList
else scan(acc ::: mapped, s3.listNextBatchOfObjects(listing))
}
scan(List(), s3.listObjects(bucket, prefix))
}
要调用上面的curry map()
函数,只需在第一个参数中传递已构造的(并且已正确初始化的)AmazonS3Client对象(请参阅官方AWS SDK for Java API Reference),存储桶名称和前缀名称名单。同时传递要应用的函数f()
以映射第二个参数列表中的每个对象摘要。
例如
val keyOwnerTuples = map(s3, bucket, prefix)(s => (s.getKey, s.getOwner))
将返回该存储桶/前缀
中(key, owner)
个元组的完整列表
或
map(s3, "bucket", "prefix")(s => println(s))
通常按Monads in Functional Programming 进行操作
答案 2 :(得分:5)
我刚刚更改了上面的代码,使用 addAll 而不是使用 for 循环来逐个添加对象,这对我有用:
List<S3ObjectSummary> keyList = new ArrayList<S3ObjectSummary>();
ObjectListing object = s3.listObjects("bucket.new.test");
keyList = object.getObjectSummaries();
object = s3.listNextBatchOfObjects(object);
while (object.isTruncated()){
keyList.addAll(current.getObjectSummaries());
object = s3.listNextBatchOfObjects(current);
}
keyList.addAll(object.getObjectSummaries());
之后,您只需使用列表 keyList 上的任何迭代器。
答案 3 :(得分:2)
如果你想获得所有对象(超过1000个键),你需要发送另一个带有最后一个键的数据包到S3。这是代码。
private static String lastKey = "";
private static String preLastKey = "";
...
do{
preLastKey = lastKey;
AmazonS3 s3 = new AmazonS3Client(new ClasspathPropertiesFileCredentialsProvider());
String bucketName = "bucketname";
ListObjectsRequest lstRQ = new ListObjectsRequest().withBucketName(bucketName).withPrefix("");
lstRQ.setMarker(lastKey);
ObjectListing objectListing = s3.listObjects(lstRQ);
// loop and get file on S3
for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
// get oject and do something.....
}
}while(lastKey != preLastKey);
答案 4 :(得分:0)
import com.amazonaws.services.s3.AmazonS3Client
import com.amazonaws.services.s3.model.{ObjectListing, S3ObjectSummary}
import scala.collection.JavaConverters._
import scala.collection.mutable.ListBuffer
def map[T](s3: AmazonS3Client, bucket: String, prefix: String)(f: (S3ObjectSummary) => T): List[T] = {
def scan(acc: ListBuffer[T], listing: ObjectListing): List[T] = {
val r = acc ++= listing.getObjectSummaries.asScala.map(f).toList
if (listing.isTruncated) scan(r, s3.listNextBatchOfObjects(listing))
else r.toList
}
scan(ListBuffer.empty[T], s3.listObjects(bucket, prefix))
}
第二种方法是使用awssdk-v2
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.1.0</version>
</dependency>
import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.{ListObjectsV2Request, S3Object}
import scala.collection.JavaConverters._
def listObjects[T](s3: S3Client, bucket: String,
prefix: String, startAfter: String)(f: (S3Object) => T): List[T] = {
val request = ListObjectsV2Request.builder()
.bucket(bucket).prefix(prefix)
.startAfter(startAfter).build()
s3.listObjectsV2Paginator(request)
.asScala
.flatMap(_.contents().asScala)
.map(f)
.toList
}
答案 5 :(得分:0)
在Scala中:
val first = s3.listObjects("bucket.new.test")
val listings: Seq[ObjectListing] = Iterator.iterate(Option(first))(_.flatMap(listing =>
if (listing.isTruncated) Some(s3.listNextBatchOfObjects(listing))
else None
))
.takeWhile(_.nonEmpty)
.toList
.flatten
答案 6 :(得分:0)
默认情况下,API最多返回1,000个键名。响应可能包含更少的键,但永远不会包含更多。 更好的实现方式是使用更新的ListObjectsV2 API:
List<S3ObjectSummary> docList=new ArrayList<>();
ListObjectsV2Request req = new ListObjectsV2Request().withBucketName(bucketName).withPrefix(folderFullPath);
ListObjectsV2Result listing;
do{
listing=this.getAmazonS3Client().listObjectsV2(req);
docList.addAll(listing.getObjectSummaries());
String token = listing.getNextContinuationToken();
req.setContinuationToken(token);
LOG.info("Next Continuation Token for listing documents is :"+token);
}while (listing.isTruncated());
答案 7 :(得分:0)
@oferei给出的代码效果很好,我赞成该代码。但我想指出@Abhishek代码的根本问题。实际上,问题出在您的do while循环中。
如果仔细观察,您将在倒数第二条语句中提取下一批对象,然后检查是否已用完文件总数。因此,当您获取最后一批时,isTruncated()变为false,并且您跳出循环并且不处理最后的X%1000记录。例如:如果总共有2123条记录,则最终将获取1000条记录,然后获取1000条记录,即2000条记录。您将错过123条记录,因为在检查isTruncated值后,当处理下一批时,isTruncated值将中断循环。
抱歉,我无法发表评论,否则我会对已投票的答案发表评论。