2013-05-31 38 views
4

我想从HttpHandler流式传输大型文件。它似乎不工作,因为它没有流式传输文件。相反,它将文件读入内存,然后将其发送回客户端。我期待所有的解决方案,并且解决方案告诉我,他们在做同样的事情时会传输文件。我的解决方案,流是这样的:流式传输大型视频文件.net

using (Stream fileStream = File.OpenRead(path)) 
{ 
    context.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(360.0)); 
    context.Response.Cache.SetCacheability(HttpCacheability.Public); 
    context.Response.AppendHeader("Content-Type", "video/mp4"); 
    context.Response.AppendHeader("content-length", file.Length); 
    byte[] buffer = new byte[1024]; 
    while (true) 
    { 
     if (context.Response.IsClientConnected) 
    { 
     int bytesRead = fileStream.Read(buffer, 0, buffer.Length); 
     if (bytesRead == 0) break; 
     context.Response.OutputStream.Write(buffer, 0, bytesRead); 
     context.Response.Flush(); 
    } 
    else 
    { 
     break; 
    } 

    } 
    context.Response.End(); 
} 

正在发生的事情是对小文件,如果我调试的代码,它会播放视频,但直到它到达context.Respond.End()线。但对于大文件,这不起作用,因为它将整个文件存储在内存中,这会带来问题。

+0

您可能希望与['IHttpAsyncHandler'](http://msdn.microsoft.com/en-us/library/system.web.ihttpasynchandler.aspx)异步实现此操作,并异步读取磁盘。 – vcsjones

+0

@ vcsjones-我不确定Async是如何工作的,但只是做了一个快速谷歌,我不知道如何解决这个问题。这似乎释放了一个线程返回到客户端异步从磁盘读取,但会返回内容,因为它仍然从磁盘读取? – Jake

回答

9

我有一个类似的问题,其中的视频必须完全下载之前播放。

我可以看到你想流式传输视频,更具体。 你必须小心编码(确保它是流式传输),不要只依赖扩展名,因为创建该文件的人可能会以更奇怪的方式构建视频,但99%的时间你应该很好。我使用mediainfo。 在你的情况应该是H.264。

它也取决于浏览器和你用什么流(除了后端代码)。就我而言,我使用了Chrome/Html5和.webm(VP8/Ogg Vorbis)。它正在为超过1G的文件工作。没有测试超过4G ...

我用视频的下载代码:

public void Video(string folder, string name) { 
     string filepath = Server.MapPath(String.Format("{0}{1}", HttpUtility.UrlDecode(folder), name)); 
     string filename = name; 

     System.IO.Stream iStream = null; 
     byte[] buffer = new Byte[4096]; 
     int length; 
     long dataToRead; 

     try { 
      // Open the file. 
      iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, 
         System.IO.FileAccess.Read, System.IO.FileShare.Read); 


      // Total bytes to read: 
      dataToRead = iStream.Length; 

      Response.AddHeader("Accept-Ranges", "bytes"); 
      Response.ContentType = MimeType.GetMIMEType(name); 

      int startbyte = 0; 

      if (!String.IsNullOrEmpty(Request.Headers["Range"])) { 
       string[] range = Request.Headers["Range"].Split(new char[] { '=', '-' }); 
       startbyte = Int32.Parse(range[1]); 
       iStream.Seek(startbyte, SeekOrigin.Begin); 

       Response.StatusCode = 206; 
       Response.AddHeader("Content-Range", String.Format(" bytes {0}-{1}/{2}", startbyte, dataToRead - 1, dataToRead)); 
      } 

      while (dataToRead > 0) { 
       // Verify that the client is connected. 
       if (Response.IsClientConnected) { 
        // Read the data in buffer. 
        length = iStream.Read(buffer, 0, buffer.Length); 

        // Write the data to the current output stream. 
        Response.OutputStream.Write(buffer, 0, buffer.Length); 
        // Flush the data to the HTML output. 
        Response.Flush(); 

        buffer = new Byte[buffer.Length]; 
        dataToRead = dataToRead - buffer.Length; 
       } else { 
        //prevent infinite loop if user disconnects 
        dataToRead = -1; 
       } 
      } 
     } catch (Exception ex) { 
      // Trap the error, if any. 
      Response.Write("Error : " + ex.Message); 
     } finally { 
      if (iStream != null) { 
       //Close the file. 
       iStream.Close(); 
      } 
      Response.Close(); 
     } 
    } 

确保您的响应报头包含了你所需要的一切。

+0

该文件编码容易,没有问题。如果直接进入浏览器,我可以在浏览器中播放该文件。什么是mediainfo?它对这个问题有什么好处。我也使用html 5,它似乎仍然不能播放大文件。我正在测试的文件大约是150 MB,它通过一个处理程序发回给浏览器html5标记的源代码,但从不播放,但如果我发送较小的文件6 MB,它没有问题 – Jake

+0

请确保httpRuntime具有maxRequestLength足够大以发送文件。 Mediainfo只是为了看视频的细节(编解码器和比特率) – Maxad

+0

我知道视频的细节。我用ffmpeg自己编码。它在浏览器中运行良好,如果我直接去它,maxRequestLength是2000000000和文件只有150MB – Jake