Я реализую версию MVC4 + WebAPI загрузки файла jQuery для BluImp, все хорошо работает с моей первоначальной попыткой, но я пытаюсь обеспечить наилучшее использование памяти при загрузке очень больших файлов (~ 2 ГБ).
Я прочитал статью Filip Woj о PushStreamContent и реализовал ее как можно лучше (удаление асинхронных частей - возможно, это проблема?). Когда я запускаю тесты и наблюдаю за TaskManager Im, не вижу много разницы в использовании памяти, и я пытаюсь понять разницу между обработкой ответов.
Здесь моя версия StreamContent:
private HttpResponseMessage DownloadContentNonChunked()
{
var filename = HttpContext.Current.Request["f"];
var filePath = _storageRoot + filename;
if (File.Exists(filePath))
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = filename
};
return response;
}
return ControllerContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "");
}
И вот моя версия PushStreamContent:
public class FileDownloadStream
{
private readonly string _filename;
public FileDownloadStream(string filePath)
{
_filename = filePath;
}
public void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
try
{
var buffer = new byte[4096];
using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read))
{
var length = (int)video.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
outputStream.Write(buffer, 0, bytesRead);
length -= bytesRead;
}
}
}
catch (HttpException ex)
{
return;
}
finally
{
outputStream.Close();
}
}
}
private HttpResponseMessage DownloadContentChunked()
{
var filename = HttpContext.Current.Request["f"];
var filePath = _storageRoot + filename;
if (File.Exists(filePath))
{
var fileDownload = new FileDownloadStream(filePath);
var response = Request.CreateResponse();
response.Content = new PushStreamContent(fileDownload.WriteToStream, new MediaTypeHeaderValue("application/octet-stream"));
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = filename
};
return response;
}
return ControllerContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "");
}
Мой вопрос: почему я не вижу большой разницы в использовании памяти между этими двумя подходами? Кроме того, Ive загрузил PDB для типа StreamContent и может видеть ссылки на размеры буфера и такие четвертые (см. Ниже), поэтому я хотел бы точно знать, что делает PushStreamContent выше и выше StreamContent. Ive проверяет информацию о типе на MSDN, но статья была немного озадачена объяснением!
namespace System.Net.Http
{
/// <summary>
/// Provides HTTP content based on a stream.
/// </summary>
[__DynamicallyInvokable]
public class StreamContent : HttpContent
{
private Stream content;
private int bufferSize;
private bool contentConsumed;
private long start;
private const int defaultBufferSize = 4096;
/// <summary>
/// Creates a new instance of the <see cref="T:System.Net.Http.StreamContent"/> class.
/// </summary>
/// <param name="content">The content used to initialize the <see cref="T:System.Net.Http.StreamContent"/>.</param>
[__DynamicallyInvokable]
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public StreamContent(Stream content)
: this(content, 4096)
{
}