Amazon s3 возвращает только 1000 записей для одного ведра и все для другого ведра (используя java sdk)?
Я использую приведенный ниже код, чтобы получить список всех имен файлов из корзины s3. У меня два ведра в с3. Для одного из сегментов ниже код возвращает все имена файлов (более 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());
Ответы
Ответ 1
Улучшение @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());
}
Ответ 2
Для разработчиков Scala здесь рекурсивная функция выполняет полное сканирование и отображение содержимого ведра AmazonS3 с использованием официального AWS SDK для Java
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))
}
Чтобы вызвать вышеупомянутую функцию curried map()
, просто передайте уже построенный (и правильно инициализированный) объект AmazonS3Client (обратитесь к официальному AWS SDK для Java API Ссылка), имя ведра и имя префикса в списке первых параметров. Также передайте функцию f()
, которую вы хотите применить, для сопоставления всех сводок объектов во втором списке параметров.
Например
val keyOwnerTuples = map(s3, bucket, prefix)(s => (s.getKey, s.getOwner))
вернет полный список кортежей (key, owner)
в этом ведре/префиксе
или
map(s3, "bucket", "prefix")(s => println(s))
как вы обычно подходите Monads в функциональном программировании
Ответ 3
Я только что изменил код выше, чтобы использовать 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());
После этого вы можете просто использовать любой итератор над списком ключей.
Ответ 4
Если вы хотите получить весь объект (более 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);
Ответ 5
- Код Paolo Angioletti не может получить все данные, только последний пакет данных.
- Я думаю, что может быть лучше использовать ListBuffer.
- Этот метод не поддерживает настройку startAfterKey.
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
}
Ответ 6
В 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