2016-06-09 15 views
11

Ich versuche, eine Datei von S3 herunterzuladen und diese Datei in einen anderen Bucket in S3 hochzuladen. Die Kopier-API funktioniert hier nicht, weil mir gesagt wurde, sie nicht zu benutzen.Wie gehe ich von io.ReadCloser zu io.ReadSeeker?

ein Objekt aus S3 Erste hat eine response.Body, dass ein io.ReadCloser ist und die Datei zu laden, nimmt die Nutzlast eine Body, die ein io.ReadSeeker ist.

Die einzige Möglichkeit, die ich herausfinden kann, ist durch Speichern der response.Body in eine Datei, dann übergibt diese Datei als io.ReadSeeker. Dies würde erfordern, die gesamte Datei zuerst auf die Festplatte zu schreiben und dann die gesamte Datei von der Festplatte zu lesen, was ziemlich falsch klingt.

Was würde Ich mag zu tun ist:

resp, _ := conn.GetObject(&s3.GetObjectInput{Key: "bla"}) 
conn.PutObject(&s3.PutObjectInput{Body: resp.Body}) // resp.Body is an io.ReadCloser and the field type expects an io.ReadSeeker 

Frage ist, wie gehe ich von einem io.ReadCloser zu einem io.ReadSeeker auf die effizienteste Art und Weise möglich?

+0

Welche spezifische API und Funktionen verwenden Sie? Ich kann nicht scheinen, die Funktionen zu finden, die Sie in dem Go S3 SDK beziehen. https://docs.aws.amazon.com/sdk-for-go/api/service/s3.html – BadZen

+0

@BadZen Ich habe die Anrufe hinzugefügt, die ich verwenden würde. – Jeff

+0

Es ist seltsam, dass Sie die Kopierfunktionen nicht verwenden können - dafür sind sie da. Vielleicht schubst du das zurück. Ihre einzige andere Option als das Schreiben der Datei auf die Festplatte besteht darin, dass Sie das GetObject() auf Ihrer 'io.ReadSeeker'-Suchanforderung erneut ausgeben und das Bereichsfeld so einstellen, dass es an der Position der Suche beginnt. Es ist in jeder Hinsicht eine schlechtere Lösung als die bereits falsche Schreib-auf-Festplatte. – BadZen

Antwort

7

io.ReadSeeker ist die Schnittstelle, die die grundlegenden Methoden Read() und Seek() gruppiert. Die Definition des Seek() Methode:

Seek(offset int64, whence int) (int64, error) 

Eine Implementierung der Seek() Methode erfordert überall in der Quelle zu suchen, in der Lage sein, die alle der Quelle erfordert verfügbar oder reproduzierbar. Eine Datei ist ein perfektes Beispiel, die Datei wird dauerhaft auf Ihrer Festplatte gespeichert und jeder Teil davon kann jederzeit gelesen werden.

response.Body ist implementiert, um von der zugrunde liegenden TCP-Verbindung zu lesen. Lesen von der zugrunde liegenden TCP-Verbindung gibt Ihnen die Daten, die der Client auf der anderen Seite sendet. Die Daten werden nicht zwischengespeichert und der Client sendet Ihnen die Daten nicht erneut auf Anfrage. Deshalb implementiert response.Body nicht io.Seeker (und damit auch io.ReadSeeker).

Um also eine io.ReadSeeker von einem io.Reader oder io.ReadCloser zu erhalten, müssen Sie etwas, das alle die Daten zwischenspeichert, so dass Anfrage auf sie überall, dass suchen können.

Dieser Cache-Mechanismus kann es in eine Datei schreiben, wie Sie erwähnt haben, oder Sie können alles in den Speicher, in einen []byte lesen ioutil.ReadAll() verwenden, und dann können Sie bytes.NewReader() verwenden, um eine io.ReadSeeker von einem []byte zu erhalten. Natürlich hat dies seine Grenzen: Der gesamte Inhalt muss in den Speicher passen, und Sie möchten vielleicht nicht die Menge an Speicher für diese Dateikopieroperation reservieren.

Alles in allem eine Implementierung von io.Seeker oder io.ReadSeeker erfordert alle Quelldaten zur Verfügung stehen, so dass Ihre beste Wette in eine Datei schreibt, oder für kleine Dateien alle in einem []byte und Streaming den Inhalt dieses Byte lesen Scheibe.

8

Verwenden Sie als Alternative github.com/aws/aws-sdk-go/service/s3/s3manager.Uploader, was einen io.Reader als Eingabe erfordert.

stelle ich mir den Grund, dass PutObject nimmt ein io.ReadSeeker anstelle eines io.Reader ist, dass Anträge unterzeichnet werden müssen, bis s3 (und eine Inhaltslänge haben), aber man kann nicht eine Signatur erzeugen, bis Sie alle Daten haben. Der Stream-y-Weg, dies zu tun wäre, die Eingabe in Chunks zu puffern, wenn sie hereinkommen, und die mehrteilige Upload-API zu verwenden, um jeden Chunk separat hochzuladen. Das ist (glaube ich) was s3manager.Uploader hinter den Kulissen tut.

Verwandte Themen