我可以在没有内容长度标题的情况下将文件上传流式传输到S3吗?

时间:2011-12-28 07:35:17

标签: http rest soap stream amazon-s3

我正在使用内存有限的计算机,我想以流方式将动态生成的(非磁盘)文件上传到S3。换句话说,我在开始上传时不知道文件大小,但最后我会知道它。通常,PUT请求具有Content-Length标头,但也许有一种解决方法,例如使用multipart或chunked content-type。

S3可以支持流式上传。例如,请看这里:

http://blog.odonnell.nu/posts/streaming-uploads-s3-python-and-poster/

我的问题是,如果不必在上传开始时指定文件长度,我可以完成同样的事情吗?

5 个答案:

答案 0 :(得分:58)

您必须通过S3's multipart API以5MiB +块上传文件。每个块都需要Content-Length,但您可以避免将大量数据(100MiB +)加载到内存中。

  • 启动S3 分段上传
  • 将数据收集到缓冲区中,直到该缓冲区达到S3的较低块大小限制(5MiB)。在构建缓冲区时生成MD5校验和。
  • 将该缓冲区上传为 Part ,存储ETag(阅读该文档)。
  • 一旦达到数据的EOF,请上传最后一个块(可能小于5MiB)。
  • 完成分段上传。

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),而不会浪费不必要的内存。


关于link to Sean O'Donnells blog

的说明

他的问题与你的不同 - 他知道并在上传前使用内容长度。他希望改善这种情况:许多库通过将文件中的所有数据加载到内存来处理上传。在伪代码中,就像这样:

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等插件轻松完成此操作。