2012-10-12 1 views
8

Ich verwende den unten erwähnten Code, um eine Liste aller Dateinamen von s3 bucket zu erhalten. Ich habe zwei Eimer in s3. Für einen der unteren Bucket-Code gibt alle Dateinamen zurück (mehr als 1000), aber der gleiche Code gibt nur 1000 Dateinamen für einen anderen Bucket. Ich verstehe einfach nicht, was passiert. Warum der gleiche Code für einen Eimer und nicht für andere?Amazon S3 gibt nur 1000 Einträge für einen Bucket zurück und alle für einen anderen Bucket (mit Java SDK)?

Auch meine Bucket haben Hierarchie Struktur Ordner/Dateiname.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()); 

Antwort

4

Improving auf @ Abhisheks eigene Antwort. Dieser Code ist etwas kürzer. Auch feste Variablennamen.

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()); 
} 
+0

Aber was ist die Ursache? Warum hatte derselbe Code für einen Fall funktioniert und nicht für einen anderen? – morsik

+0

Das ist eine gute Frage, auf die ich keine Antwort habe. Ich habe nur @ Abhisheks Code genommen und ihn "repariert". Meine einzige Vermutung ist, dass es eine Eigenschaft des Eimers ist. – oferei

+1

Ich habe das gleiche Problem mit "alten" Version von s3 Java API. Amazon führte "v2" ein, das das Problem beheben sollte: http://docs.aws.amazon.com/AmazonS3/latest/dev/ListingObjectKeysUsingJava.html Hinweis, es verwendet 's3client.listObjectsV2' und' req.setContinuationToken (result.getNextContinuationToken()) '. Die letzte sollte separate REST GET-Aufrufe an s3 vornehmen (da einzelne get-Schlüssel standardmäßig bis zu 1000 Schlüssel zurückgeben, http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html) – morsik

4

Ich habe gerade über Code ändern addAll verwenden statt für Schleife unter Verwendung von Objekt eins nach dem anderen hinzufügen und es funktionierte für mich. Code-Änderungen sind:

 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()); 

Danach können Sie einfach jeden iterater über Liste keyList verwenden können.

+0

Ich empfehle die Verwendung von keyList.addAll (x) anstelle der Zuordnung zu keyList. Auf diese Weise ändern Sie später nicht ein privates Mitglied von ObjectListing (das von getObjectSummaries zurückgegeben wurde) mit addAll. Und da Sie bereits eine Liste in der ersten Zeile zugewiesen haben, sind Sie fertig. – oferei

1

Wenn Sie alle Objekte (mehr als 1000 Schlüssel) abrufen möchten, müssen Sie ein weiteres Paket mit dem letzten Schlüssel an S3 senden. Hier ist der Code.

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); 
6

Für Scala-Entwickler, hier ist es rekursive Funktion ein Scan und Karte der Inhalt eines AmazonS3 Eimer mit dem amtlichen AWS SDK for 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)) 
} 

aufzurufen die oben curried auszuführen map() Funktion übergeben Sie einfach das bereits erstellte (und ordnungsgemäß initialisierte) AmazonS3Client-Objekt (siehe den offiziellen AWS SDK for Java API Reference), den Bucket-Namen und den Präfixnamen in der ersten Parameterliste. Übergeben Sie auch die Funktion f(), die Sie anwenden möchten, um jede Objektzusammenfassung in der zweiten Parameterliste zuzuordnen.

Zum Beispiel

val keyOwnerTuples = map(s3, bucket, prefix)(s => (s.getKey, s.getOwner)) 

wird die vollständige Liste der (key, owner) Tupel in diesem Eimer/Präfix zurückkehren

oder

map(s3, "bucket", "prefix")(s => println(s)) 

wie gewohnt Ansatz von Monads in Functional Programming

Verwandte Themen