您必须通过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),而不会不必要地浪费内存。
他的问题与您的不同 - 他知道并在上传之前使用 Content-Length。他想改进这种情况:许多库通过将文件中的所有数据加载到内存中来处理上传。在类似这样的伪代码中:
data = File.read(file_name)
request = new S3::PutFileRequest()
request.setHeader('Content-Length', data.size)
request.setBody(data)
request.send()
他的解决方案是通过文件系统 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()