Какова наилучшая стратегия для загрузки большого файла с использованием HttpClient в телефонном аппарате с низкой памятью?
Я пытаюсь загрузить файлы с использованием аналогичного подхода HttpClient: как загрузить сразу несколько файлов
в телефоне Windows.
using (var content = new MultipartFormDataContent())
{
content.Add(CreateFileContent(imageStream, "image.jpg", "image/jpeg"));
content.Add(CreateFileContent(signatureStream, "image.jpg.sig", "application/octet-stream"));
var response = await httpClient.PostAsync(_profileImageUploadUri, content);
response.EnsureSuccessStatusCode();
}
private StreamContent CreateFileContent(Stream stream, string fileName, string contentType)
{
var fileContent = new StreamContent(stream);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"files\"",
FileName = "\"" + fileName + "\""
}; // the extra quotes are key here
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return fileContent;
}
Это прекрасно работает при загрузке небольших файлов. Если я попытался загрузить более крупный файл (скажем, > 50 МБ) в устройстве с низким уровнем (512 Мб памяти)
он выдает System.OutOfMemoryException. Я использовал диагностические инструменты для мониторинга потребления памяти и заметил, что память
экспоненциально растет во время вызова PostAsync. Кажется, он копирует весь контент в память. Прямо сейчас у нас нет поддержки каналов в
апи.
Какова наилучшая стратегия для загрузки большого файла с использованием HttpClient в телефонном аппарате с низкой памятью?
Ответы
Ответ 1
Сделайте многопользовательский POST вручную - без помощи MultipartFormDataContent
Если вы должны отправить его многостраничным, вы можете отправить его более вручную, прочитав из исходного файла в блоках буфера 4k.
Вам не обязательно делать это с помощью методов async. Решение представляет собой "ручное управление буферизацией 4k". Но async был бы идеальным, будучи наиболее эффективным потоком/ЦП.
Здесь другая рекомендуемая ссылка, чтобы понять, как кодовое многостраничное сообщение. И еще один для понимания протокола, вот пример того, что отправляется по потоку, иллюстрирующий маркеры границ
Кроме того, в архитектуре я предпочитаю загружать файлы отдельно для любых (форм) данных. Это позволяет полностью отказаться от многопользовательской проводки, делая ваши API-интерфейсы атомарными и простыми. У вас может быть служба, которая просто хранит загруженный файл и возвращает URL-адрес или идентификатор. Затем этот URL-адрес или идентификатор можно будет ссылаться на ваши данные и опубликовать впоследствии.
Ответ 2
Я не являюсь экспертом в MultipartFormDataContent (и он может разделить контент под водой), но подсказка может заключаться в том, что вы делите данные, которые хотите отправить.
Затем отправьте другие блоки и восстановите их на принимающей стороне.
например. разделите изображения в меньших блоках (например, 10 Мб или меньше в зависимости от использования памяти) и отправьте эти
Таким образом, это может привести к тому, что цикл for будет перемещаться по блокам.
foreach (byte[] block in dividedContent)
{
using (var content = new MultipartFormDataContent())
{
content.Add(block);
var response = await httpClient.PostAsync(_profileImageUploadUri, content);
response.EnsureSuccessStatusCode();
}
}
возможно, что-то подобное решит вашу проблему:)