Лучший способ потоковой передачи файлов в ASP.NET
Какой лучший способ потоковой передачи файлов с помощью ASP.NET?
Для этого существуют различные методы, и я в настоящее время использую метод Response.TransmitFile() внутри обработчика http, который отправляет файл в браузер напрямую. Это используется для различных вещей, включая отправку FLV извне webroot во встроенный Flash-плеер.
Однако это не похоже на надежный метод. В частности, есть странная проблема с Internet Explorer (7), где браузер просто зависает после просмотра видео или двух. Нажатие на какие-либо ссылки и т.д. Не имеет никакого эффекта, и единственный способ заставить вещи снова работать на сайте - закрыть браузер и снова открыть его.
Это также происходит в других браузерах, но гораздо реже. Основываясь на некоторых базовых тестах, я подозреваю, что это связано с тем, как файлы передаются... возможно, соединение не закрывается должным образом или что-то в этих строках.
Попробовав несколько разных вещей, я обнаружил, что для меня работает следующий метод:
Response.WriteFile(path);
Response.Flush();
Response.Close();
Response.End();
Это касается проблемы, упомянутой выше, и просмотр видео больше не приводит к зависанию Internet Explorer.
Тем не менее, я понимаю, что Response.WriteFile() сначала загружает файл в память, и при условии, что некоторые потоковые файлы могут потенциально быть довольно большим, это не похоже на идеальное решение.
Мне интересно узнать, как другие разработчики пересылают большие файлы в ASP.NET и, в частности, потоковые видеофайлы FLV.
Ответы
Ответ 1
Я бы взял вещи за пределами конвейера aspx. В частности, я бы написал обработчик (ashx, или сопоставленный через config), который выполняет минимальную работу и просто записывает ответ в куски. Обработчик будет принимать входные данные из строки запроса/формы как обычно, находить объект в потоке и передавать данные (используя локальный буфер среднего размера в цикле). Простой (неполный) пример, показанный ниже:
public void ProcessRequest(HttpContext context) {
// read input etx
context.Response.Buffer = false;
context.Response.ContentType = "text/plain";
string path = @"c:\somefile.txt";
FileInfo file = new FileInfo(path);
int len = (int)file.Length, bytes;
context.Response.AppendHeader("content-length", len.ToString());
byte[] buffer = new byte[1024];
Stream outStream = context.Response.OutputStream;
using(Stream stream = File.OpenRead(path)) {
while (len > 0 && (bytes =
stream.Read(buffer, 0, buffer.Length)) > 0)
{
outStream.Write(buffer, 0, bytes);
len -= bytes;
}
}
}
Ответ 2
Взгляните на следующую статью Отслеживание и возобновление загрузки больших файлов в ASP.NET, которая даст вам больше информации, чем просто открыть поток и выбивать все биты.
HTTP-протокол поддерживает запросы байтов с распределенным байтом и возобновляемые загрузки, и многие потоковые клиенты (например, видеоплееры или Adobe pdf) могут и будут пытаться объединить их, сэкономить пропускную способность и дать вашим пользователям лучший опыт.
Не тривиально, но это время хорошо проведено.
Ответ 3
Попробуйте открыть файл в виде потока, а затем с помощью Response.OutputStream.Write(). Например:
Изменить: Плохо, я забыл, что Write берет байтовый буфер. Фиксированный
byte [] buffer = new byte[1<<16] // 64kb
int bytesRead = 0;
using(var file = File.OpenRead(path))
{
while((bytesRead = file.Read(buffer, 0, buffer.Length)) != 0)
{
Response.OutputStream.Write(buffer, 0, bytesRead);
}
}
Response.Flush();
Response.Close();
Response.End();
Изменить 2: Пробовали ли вы это? Он должен работать.
Ответ 4
После попытки множества разных комбинаций, в том числе кода, размещенного в различных ответах, кажется, что установка Response.Buffer = true перед вызовом TransmitFile сделала трюк, и веб-приложение стало намного более восприимчивым в Internet Explorer.
В этом конкретном случае расширение SWF также отображается на ASP.NET, и мы используем собственный обработчик в нашем веб-приложении для чтения файлов с диска, а затем отправляем их в браузер с помощью Response.TransmitFile(), У нас есть Flash-видеопроигрыватель для воспроизведения видеофайлов, которые также являются SWF, и я думаю, что все эти действия проходят через обработчик без буферизации, что, возможно, вызывало странные вещи в IE.