Sie müssen Ihre Datei in 5MiB + Chunks über die mehrteilige API von S3 hochladen . Jeder dieser Blöcke erfordert eine Inhaltslänge, aber Sie können vermeiden, große Datenmengen (100 MB +) in den Speicher zu laden.
- Initiieren Sie den S3 Multipart Upload .
- Sammeln Sie Daten in einem Puffer, bis dieser Puffer die untere Blockgrößengrenze von S3 (5 MB) erreicht. Generieren Sie beim Aufbau des Puffers eine MD5-Prüfsumme.
- Laden Sie diesen Puffer als Teil hoch, speichern Sie das ETag (lesen Sie die Dokumente dazu).
- Sobald Sie EOF Ihrer Daten erreicht haben, laden Sie den letzten Block hoch (der kleiner als 5 MB sein kann).
- Schließen Sie den mehrteiligen Upload ab.
S3 erlaubt bis zu 10.000 Teile. Wenn Sie also eine Teilegröße von 5 MB auswählen, können Sie dynamische Dateien mit bis zu 50 GB hochladen. Sollte für die meisten Anwendungsfälle ausreichen.
Allerdings: Wenn Sie mehr benötigen, müssen Sie Ihre Teilegröße erhöhen. Entweder durch Verwendung einer höheren Teilegröße (z. B. 10 MB) oder durch Erhöhen während des Uploads.
First 25 parts: 5MiB (total: 125MiB)
Next 25 parts: 10MiB (total: 375MiB)
Next 25 parts: 25MiB (total: 1GiB)
Next 25 parts: 50MiB (total: 2.25GiB)
After that: 100MiB
Auf diese Weise können Sie Dateien mit bis zu 1 TB hochladen (S3-Limit für eine einzelne Datei beträgt derzeit 5 TB), ohne unnötig Speicherplatz zu verschwenden.
Sein Problem unterscheidet sich von Ihrem - er kennt und verwendet die Inhaltslänge vor dem Hochladen. Er möchte diese Situation verbessern: Viele Bibliotheken verarbeiten Uploads, indem sie alle Daten aus einer Datei in den Speicher laden. Im Pseudocode wäre das ungefähr so:
data = File.read(file_name)
request = new S3::PutFileRequest()
request.setHeader('Content-Length', data.size)
request.setBody(data)
request.send()
Seine Lösung macht es, indem er das Content-Length
über die Dateisystem-API erhält . Anschließend überträgt er die Daten von der Festplatte in den Anforderungsdatenstrom. Im Pseudocode:
upload = new S3::PutFileRequestStream()
upload.writeHeader('Content-Length', File.getSize(file_name))
upload.flushHeader()
input = File.open(file_name, File::READONLY_FLAG)
while (data = input.read())
input.write(data)
end
upload.flush()
upload.close()