Je travaille sur une machine avec une mémoire limitée et j'aimerais télécharger un fichier généré dynamiquement (pas à partir du disque) en streaming sur S3. En d'autres termes, je ne connais pas la taille du fichier lorsque je démarre le téléchargement, mais je le saurai à la fin. Normalement, une demande PUT a un en-tête Content-Length, mais il existe peut-être un moyen de contourner cela, comme l'utilisation d'un type de contenu en plusieurs parties ou en morceaux.
S3 peut prendre en charge les téléchargements en continu. Par exemple, voir ici:
http://blog.odonnell.nu/posts/streaming-uploads-s3-python-and-poster/
Ma question est, puis-je accomplir la même chose sans avoir à spécifier la longueur du fichier au début du téléchargement?
Vous devez télécharger votre fichier en morceaux de 5 Mo + via API multipartie de S . Chacun de ces morceaux nécessite une longueur de contenu, mais vous pouvez éviter de charger d'énormes quantités de données (100 Mo +) en mémoire.
S3 permet jusqu'à 10 000 pièces. Ainsi, en choisissant une taille de pièce de 5 Mo, vous pourrez télécharger des fichiers dynamiques jusqu'à 50 Go. Devrait être suffisant pour la plupart des cas d'utilisation.
Cependant: si vous en avez besoin de plus, vous devez augmenter la taille de votre pièce. Soit en utilisant une taille de pièce plus élevée (10 Mo par exemple), soit en l'augmentant lors du téléchargement.
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
Cela vous permettra de télécharger des fichiers jusqu'à 1 To (la limite de S3 pour un seul fichier est de 5 To en ce moment) sans gaspiller la mémoire inutilement.
Son problème est différent du vôtre - il connaît et utilise la longueur de contenu avant le téléchargement. Il souhaite améliorer cette situation: de nombreuses bibliothèques gèrent les téléchargements en chargeant toutes les données d'un fichier dans la mémoire. En pseudo-code, ce serait quelque chose comme ceci:
data = File.read(file_name)
request = new S3::PutFileRequest()
request.setHeader('Content-Length', data.size)
request.setBody(data)
request.send()
Sa solution le fait en obtenant le Content-Length
via l'API du système de fichiers. Il diffuse ensuite les données du disque dans le flux de demandes. En pseudo-code:
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()
Mettre cette réponse ici pour les autres au cas où cela aiderait:
Si vous ne connaissez pas la longueur des données que vous diffusez sur S3, vous pouvez utiliser S3FileInfo
Et sa méthode OpenWrite()
pour écrire des données arbitraires dans S3.
var fileInfo = new S3FileInfo(amazonS3Client, "MyBucket", "streamed-file.txt");
using (var outputStream = fileInfo.OpenWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
streamWriter.WriteLine("Hello world");
// You can do as many writes as you want here
}
}
Vous pouvez utiliser l'outil de ligne de commande gof3r pour simplement diffuser des canaux Linux:
$ tar -czf - <my_dir/> | gof3r put --bucket <s3_bucket> --key <s3_object>
Reportez-vous aux demandes d'entités en plusieurs parties HTTP. Vous pouvez envoyer un fichier sous forme de blocs de données à la cible.
Si vous utilisez Node.js, vous pouvez utiliser un plugin comme s3-streaming-upload pour accomplir cela assez facilement.