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

Tyl*_*ler 55 rest soap http stream amazon-s3

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

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

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

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

Mar*_*rth 60

您必须通过S3的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
Run Code Online (Sandbox Code Playgroud)

这将允许您上传最高1TB的文件(S3的单个文件限制为5TB),而不会浪费不必要的内存.


关于您与Sean O'Donnells博客链接的说明:

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

data = File.read(file_name)
request = new S3::PutFileRequest()
request.setHeader('Content-Length', data.size)
request.setBody(data)
request.send()
Run Code Online (Sandbox Code Playgroud)

他的解决方案是Content-Length通过文件系统API 获取它.然后,他将数据从磁盘流式传输到请求流中.在伪代码中:

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()
Run Code Online (Sandbox Code Playgroud)

  • 我在 https://github.com/alexmojaki/s3-stream-upload 创建了一个专门用于此的开源库 (2认同)

mwr*_*son 5

把这个答案放在这里给其他人以防万一它有帮助:

如果您不知道要流式传输到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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • S3FileInfo实际上在提交其内容之前缓冲整个流. (9认同)
  • Java 中是否有与这些类等效的类? (2认同)

web*_*rst 5

您可以使用gof3r命令行工具来流式传输linux管道:

$ tar -czf - <my_dir/> | gof3r put --bucket <s3_bucket> --key <s3_object>
Run Code Online (Sandbox Code Playgroud)