Самый эффективный способ записи больших файлов в HttpResponse в ASP.NET - PullRequest
1 голос
/ 29 апреля 2011

Я создаю ZIP-файл на лету. Я использую dotnetzip для этого. Размер моего ZIP-файла может достигать 500 МБ, и многие пользователи пытаются загрузить его одновременно.

Каким самым эффективным способом я могу подавать файлы? Если бы у меня был выбор, я бы тоже не стал сохранять файлы на диск, так как это может привести к серьезным ограничениям на диске.

Редактировать: Подробнее о моем случае использования:

Мы размещаем наши файлы в библиотеке ресурсов SharePoint 2010, размещенной на сайте интрасети, в которой работают пользователи по всему миру. Размер файлов обычно составляет от 10 до 80 МБ. Пользователи хотели бы иметь возможность загружать несколько файлов одновременно.

Ответы [ 2 ]

2 голосов
/ 29 апреля 2011

Ну, в теории :

Для традиционного приложения ASP.Net вы должны просто иметь возможность записать данные ответа (байты) в HttpContext.Response.OutputStream (то, как вы получите HTTP-контекст ответа, будет зависеть от того, как вы обрабатываете запрос на загрузку, например, если вы реализуете IHttpHandler тогда вы получите http-контекст, переданный вам).

Глядя на примеры DotNetZip, похоже, что Save метод принимает поток, так что это будет так же просто, как

zip.Save(context.Response.OutputStream);

Если zip-файл повторно используется и загружается многими пользователями, вы можете вместо этого записать zip-файл в MemoryStream при создании zip-файла, который позволяет позднее копировать содержимое этого потока памяти в отдельные ответы:

MemoryStream stream = new MemoryStream()
zip.Save(stream);
// Save data somewhere common (e.g. cache it)
byte[] data = stream.ToArray();

Чтобы записать эти данные обратно в ответ:

MemoryStream reader = new MemoryStream(data);
CopyStream(reader, context.Response.OutputStream);

См. Лучший способ копирования между двумя экземплярами Stream - C # для реализации CopyStream.

Однако на самом деле :

Если подумать об этом на секунду, это означает, что если размер zip-файла составляет 500 МБ, мы храним 500 МБ данных в памяти - это может быть хорошо, если это единственный zip-файл, существовавший когда-либо, но если существует 3 или 4 мы быстро исчерпаем «память» (т. е. виртуальное адресное пространство).

Решение? Боюсь, что самый простой способ - сохранить ваш zip-файл в файл (даже если это временный файл, который не обслуживается непосредственно IIS), а не в потоке памяти:

// To save the zip
string filename = Path.GetTempFileName();
zip.Save(filename);

// To write the file
context.Response.TransmitFile(filename);

Вы, вероятно, также должны удалить файл, когда закончите.

Обратите внимание, что вам нужно беспокоиться об этом, только если вы решили разделить один и тот же zip между несколькими пользователями - если вы просто создаете zip для каждого пользователя и записываете его непосредственно в выходной поток, используя zip.Save(OutputStream), тогда все намного меньше хлопот. Я бы посоветовал сначала просто сделать это простым способом, а затем проверить, есть ли у вас проблемы с производительностью, которые можно решить, создав один раз zip.

1 голос
/ 29 апреля 2011

Для этого вам, вероятно, лучше работать асинхронно, используя очередь сообщений.Таким образом, архивирование добавляется в очередь, и вы получаете либо один сервер, либо несколько серверов.Я не знаю, соответствует ли это вашим требованиям.

Я использовал Rabbit MQ (http://www.rabbitmq.com/) раньше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...