Вы должны загрузить свой файл в 5MiB + чанках через multipart API S3 . Для каждого из этих блоков требуется длина содержимого, но вы можете избежать загрузки в память огромных объемов данных (100 МБ +).
- Инициирование S3 Многоэтапная загрузка .
- Собирайте данные в буфер, пока этот буфер не достигнет нижнего предела размера фрагмента S3 (5 МБ). Генерация контрольной суммы MD5 при создании буфера.
- Загрузите этот буфер как Part , сохраните ETag (прочитайте документы по нему).
- Как только вы достигнете EOF ваших данных, загрузите последний кусок (который может быть меньше, чем 5MiB).
- Завершение многочастной загрузки.
S3 позволяет до 10 000 деталей. Таким образом, выбрав размер 5 МБ, вы сможете загружать динамические файлы до 50 ГБ. Должно быть достаточно для большинства случаев использования.
Однако: если вам нужно больше, вы должны увеличить свой размер детали. Либо используя больший размер детали (например, 10 МБ), либо увеличив его во время загрузки.
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
Это позволит вам загружать файлы размером до 1 ТБ (ограничение S3 для одного файла сейчас составляет 5 ТБ) без лишних затрат памяти.
Его проблема отличается от вашей - он знает и использует Content-Length перед загрузкой. Он хочет улучшить ситуацию: многие библиотеки обрабатывают загрузку, загружая все данные из файла в память. В псевдокоде это будет примерно так:
data = File.read(file_name)
request = new S3::PutFileRequest()
request.setHeader('Content-Length', data.size)
request.setBody(data)
request.send()
Его решение делает это путем получения 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()