2009-03-03 16 views
34

Was ist der beste Weg zum Streamen von Dateien mit ASP.NET?Die beste Methode zum Streamen von Dateien in ASP.NET

Es scheint verschiedene Methoden dafür zu geben, und ich verwende derzeit die Response.TransmitFile() Methode in einem http-Handler, der die Datei direkt an den Browser sendet. Dies wird für verschiedene Zwecke verwendet, einschließlich des Sendens von FLVs von außerhalb der Webroot an einen eingebetteten Flash-Videoplayer.

Dies scheint jedoch keine zuverlässige Methode zu sein. Insbesondere gibt es ein seltsames Problem mit Internet Explorer (7), wo der Browser nur hängt, nachdem ein oder zwei Videos angesehen werden. Das Klicken auf irgendwelche Links usw. hat keine Wirkung, und die einzige Möglichkeit, Dinge wieder zum Laufen zu bringen, besteht darin, den Browser zu schließen und wieder zu öffnen.

Dies tritt auch in anderen Browsern auf, aber viel seltener. Basierend auf einigen grundlegenden Tests vermute ich, dass dies etwas mit der Art und Weise zu tun hat, wie Dateien gestreamt werden ... vielleicht wird die Verbindung nicht richtig geschlossen oder etwas in dieser Richtung.

Nach ein paar verschiedenen Dinge auszuprobieren, habe ich festgestellt, dass die folgende Methode funktioniert für mich:

Response.WriteFile(path); 
Response.Flush(); 
Response.Close(); 
Response.End(); 

Dies wird, um das Problem oben erwähnt, und Betrachten von Videos führt nicht mehr Internet Explorer zu hängen.

Allerdings ist mein Verständnis, dass Response.WriteFile() lädt die Datei zuerst in den Speicher, und da einige Dateien Streaming möglicherweise sehr groß sein könnte, scheint dies nicht wie eine ideale Lösung.

Ich bin interessiert zu hören, wie andere Entwickler große Dateien in ASP.NET streamen und insbesondere FLV-Videodateien streamen.

+0

Hier ist ein Ansatz, den ich verwendet, die fortsetzbare Download-Funktionalität hinzugefügt, die nützlich wäre, wenn Video-Streaming: http://Stackoverflow.com/a/6475414/222748 – Michael

Antwort

8

Versuchen Sie, die Datei als Stream zu öffnen, und verwenden Sie dann Response.OutputStream.Write(). Zum Beispiel:

Edit: Meine schlechte, ich habe vergessen, dass Write einen Byte-Puffer nimmt. Feste

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(); 

Edit 2: Haben Sie dies versuchen? Es sollte funktionieren.

+0

Danke, aber ich glaube nicht, dass das funktioniert ... Antwort. OutputStream.Write benötigt keinen Stream-Parameter (jedenfalls nicht in ASP.NET 2.0), nur ein Byte-Array, das erfordert, dass die Datei zuerst in den Speicher geladen wird und daher nicht wirklich besser ist als die WriteFile-Lösung. – Mun

+0

Ja, ich habe nicht aufgepasst, als ich den Code schrieb. Behoben – Randolpho

+2

In Bezug auf das Byte-Array - Sie müssen nicht den gesamten Stream in den Speicher laden. Der Code, den ich verwende, verwendet während des Streamen höchstens 64 KB Arbeitsspeicher (plus geringen Overhead). – Randolpho

51

Ich würde Dinge außerhalb der "aspx" -Pipeline nehmen. Insbesondere würde ich einen Ran-Handler schreiben (ashx oder über config gemappt), der die minimale Arbeit macht, und einfach in die Antwort in Chunks schreibt. Der Handler würde die Eingabe von der Abfragezeichenfolge/Formular als normal akzeptieren, das zu streuende Objekt lokalisieren und die Daten streamen (indem ein lokaler Puffer mittlerer Größe in einer Schleife verwendet wird). Eine einfache (unvollständige) Beispiel unten gezeigt:

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; 
     } 
    } 
} 
+1

Ein Downvote ohne Grund hilft niemandem. Ich dachte, deine Antwort sei gut. +1, um dich wieder zur Parität zu bringen. – Guy

+0

Ich bin nicht derjenige, der downvoted, aber dachte, ich würde darauf hinweisen, dass die erste Frage tatsächlich besagt, dass der Code in einem http-Handler verwendet wird ... Danke für den Vorschlag trotzdem. – Mun

+1

Um den Namen der Datei zu ändern, nach Zeile: 'context.Response ...' fügen Sie diese Zeile hinzu: 'context.Response.AppendHeader (" content-Disposition "," Anhang; Dateiname = "+ Dateiname);' – MaciejLisCK

10

Werfen Sie einen Blick auf die folgenden Artikel Tracking and Resuming Large File Downloads in ASP.NET die Sie mehr in die Tiefe geben als nur einen Stream öffnen und alle Bits rausschmeißen.

Das http-Protokoll unterstützt entfernte Byteanfragen und fortsetzbare Downloads, und viele Streaming-Clients (wie Videoplayer oder Adobe PDF) können und werden versuchen, diese aufzuteilen, was Bandbreite spart und Ihren Benutzern ein besseres Erlebnis bietet.

Nicht trivial, aber es ist Zeit gut angelegt.

3

Nach dem Ausprobieren vieler verschiedener Kombinationen, einschließlich des in den verschiedenen Antworten geposteten Codes, scheint es so zu sein, dass Response.Buffer = true vor dem Aufruf von TransmitFile eingestellt wurde und die Webanwendung in Internet Explorer jetzt viel reaktionsfähiger ist. In diesem speziellen Fall wird die SWF-Erweiterung auch ASP.NET zugeordnet, und wir verwenden einen benutzerdefinierten Handler in unserer Webanwendung, um die Dateien von der Festplatte zu lesen und sie dann mithilfe von Response.TransmitFile an den Browser zu senden.). Wir haben einen Flash-basierten Videoplayer, um Videodateien abzuspielen, die auch SWFs sind, und ich denke, dass all diese Aktivitäten durch den Handler ohne Pufferung gehen können, was seltsame Dinge im IE verursacht haben könnte.

Verwandte Themen