我正在使用内存有限的计算机,我想以流方式将动态生成的(非磁盘)文件上传到S3。换句话说,我在开始上传时不知道文件大小,但最后我会知道它。通常,PUT请求具有Content-Length标头,但也许有一种解决方法,例如使用multipart或chunked content-type。
S3可以支持流式上传。例如,请看这里:
http://blog.odonnell.nu/posts/streaming-uploads-s3-python-and-poster/
我的问题是,如果不必在上传开始时指定文件长度,我可以完成同样的事情吗?
答案 0 :(得分:58)
您必须通过S3's multipart API以5MiB +块上传文件。每个块都需要Content-Length,但您可以避免将大量数据(100MiB +)加载到内存中。
S3允许最多10,000个零件。因此,通过选择5MiB的零件尺寸,您将能够上传最高50GiB的动态文件。对于大多数用例来说应该足够了。
但是:如果您需要更多,则必须增加零件尺寸。通过使用更高的部件尺寸(例如10MiB)或在上传期间增加它。
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
这将允许您上传最高1TB的文件(S3的单个文件限制为5TB),而不会浪费不必要的内存。
他的问题与你的不同 - 他知道并在上传前使用内容长度。他希望改善这种情况:许多库通过将文件中的所有数据加载到内存来处理上传。在伪代码中,就像这样:
data = File.read(file_name)
request = new S3::PutFileRequest()
request.setHeader('Content-Length', data.size)
request.setBody(data)
request.send()
他的解决方案是通过filesystem-API获取Content-Length
。然后,他将数据从磁盘流式传输到请求流中。在伪代码中:
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()
答案 1 :(得分:7)
如果有帮助,请将此答案放在其他地方:
如果您不知道要流式传输到S3的数据的长度,可以使用S3FileInfo
及其OpenWrite()
方法将任意数据写入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
}
}
答案 2 :(得分:5)
您可以使用gof3r命令行工具来流式传输linux管道:
$ tar -czf - <my_dir/> | gof3r put --bucket <s3_bucket> --key <s3_object>
答案 3 :(得分:1)
详细了解HTTP多部分实体请求。您可以将文件作为数据块发送到目标。
答案 4 :(得分:1)
如果您使用的是Node.js,则可以使用s3-streaming-upload等插件轻松完成此操作。