Mehr von Jürgen Gutsch

Mehr von Jürgen Gutsch

Empfehlungen von Jürgen Gutsch

Blog-Empfehlungen von Jürgen Gutsch

Willkommen bei ASP.NET Zone. Anmelden | Registrieren | Hilfe

Jürgen Gutsch

ASP.NET und mehr...

News

Große Dateien aus einer Datenbank lesen und zum Download bereitstellen.

in dem Beitrag "Große Dateien in hochladen und in eine Datenbank schreiben" habe ich beschrieben, wie man Dateien performant in die Datenbank schreiben kann. Umgekehrt sollten die Werte ja auch wieder ausgelesen werden. Auch hier gibt es in der MSDN wieder einen Artikel dazu: Abrufen von BLOB-Werten aus einer Datenbank

Unten habe ich ein Beispielprojekt verlinkt in dem gezeigt wird, wie die vom Microsoft beschriebene Methode in einer ASP.NET Anwendung genutzt werden kann, um Dateien aus der Datenbank auszulesen und über einen HttpHandler zum Download bereit zu stellen.

Das Auslesen der Daten ist im Vergleich zum schreiben wesentlich einfacher und mit reinen ADO.NET Möglichkeiten umzusetzen. Der Trick hierbei ist, dass man dem DataReader (mit Hilfe des CommandBehaviors  "SequentialAccess") sagen kann, dass er die Daten nicht komplett aus der Datenbank laden soll, sondern als Stream:

SqlDataReader myReader = comd.ExecuteReader(CommandBehavior.SequentialAccess);

Anschließend könne die Binärdaten mit GetBytes() stückchenweise über den DataReader aus der Datenbank ausgelesen werden:

int bufferLen = 1024; 
byte[] buffer = new byte[bufferLen];
long retval;
long offset = 0;
[...]
if (myReader.Read())
{
    using (BinaryWriter bw = new BinaryWriter(OutputStream))
    {
        retval = myReader.GetBytes(0, offset, buffer, 0, bufferLen); 
        while (retval == bufferLen)
        {
            bw.Write(buffer);
            bw.Flush(); 
            offset += bufferLen;
            retval = myReader.GetBytes(0, offset, buffer, 0, bufferLen);
        } 
        bw.Write(buffer, 0, (int)retval - 1);
        bw.Flush();
        bw.Close();
    }
}

Auch hier bestimmt die Puffergröße (bufferLen) nicht nur Größe der Datenpakete, sondern auch die Anzahl der Schleifendurchläufe. Ein niedriger Wert erhöht die Schleifendurchläufe reduziert den Speicherbedarf, erhöht aber die Prozessorlast. Umgekehrt verringert ein höherer Wert die Prozessorlast, erhöht aber den Speicherbedarf. Man sollte also mit der Größe spielen um den perfekten Mittelwert zu finden.

Genauso wie in dem vorhergehenden Artikel aus dem vorhandenen Stream partiell gelesen wird, wird hier Stück für Stück in einen Steam geschrieben. Der Stream kann dann der aktuelle OutpuStream eines generischen HttpHandlers sein. Die ProzessRequest Methode des generischen HttpHandlers könnte dann wie folgt aussehen:



public void ProcessRequest(HttpContext context)
{
    int id = 0;
    if (!int.TryParse(context.Request.QueryString[id], out id))
        return
    MyFile file = BinaryManager.ReadFile(id);
    if (file == null)
        return
    context.Response.ContentType = file.ContentType;
    context.Response.AddHeader("Content-Disposition",
        "attachment; filename=" +
        System.IO.Path.GetFileName(file.FileName));
    context.Response.AddHeader("Content-Length", file.FileSize.ToString()); 
    BinaryManager.ReadFromDB(context.Response.OutputStream, id);
}

Übrigenz macht es Sinn jede große Datei, egal ob sie aus der Datenbank kommt oder nicht, in so einer Schleife, stückchenweise in den ResponseStream zu schreiben. Der Browser muss auf diese Art nicht zu lange auf eine erste Reaktion vom Webserver warten. Der Download funktioniert dan schneller und flüssiger.

Beispielprojekt: download (228KB)

Posted: Samstag, 22. November 2008 09:45 von Jürgen Gutsch

Kommentare

Peter Bucher sagte:

Hallo Jürgen

Danke für den Post.

Dieselbe Vorgehensweise (Schreiben mit Buffer und Flush) kann man auch beim Download von grossen Dateien bspw. vom Filesystem gebrauchen.

# November 23, 2008 03:14

Jürgen Gutsch sagte:

Salli Peter,

ja, dass hatte ich am schluss gemeint. Im Prinzip lässt sich die Methode überall dort verwenden wo es darum geht große Daten von einen Stream in den anderen zu bekommen.

# November 23, 2008 09:05

Peter Bucher sagte:

Hoi Jürgen

Axso, hab ich überlesen - gut :)

# November 23, 2008 13:57
Anonyme Kommentare sind nicht zugelassen