2009-07-03 5 views
19

Ich muss eine große Datei (2   GB) über HTTP in einer C# -Konsolenanwendung herunterladen. Problem ist, nach etwa 1.2   GB, läuft die Anwendung aus dem Speicher.Wie lade ich eine große Datei (über HTTP) in .NET herunter?

Hier ist der Code, den ich mit:

WebClient request = new WebClient(); 
request.Credentials = new NetworkCredential(username, password); 
byte[] fileData = request.DownloadData(baseURL + fName); 

Wie Sie sehen können ... Ich bin die Datei direkt in den Speicher zu lesen. Ich bin mir ziemlich sicher, dass ich das lösen könnte, wenn ich die Daten in Blöcken aus HTTP lesen und in eine Datei auf der Festplatte schreiben würde.

Wie könnte ich das tun?

Antwort

34

Wenn Sie WebClient.DownloadFile verwenden, können Sie es direkt in eine Datei speichern.

+0

Genius zu verwenden. Das hat am Ende einen Traum erfüllt. Danke für Ihre Hilfe! –

+0

FYI. Das Testen einer Klasse wie WebClient, die keine Schnittstellen implementiert, kann eine Herausforderung sein. – Krishter

9

Sie müssen den Antwortstream abrufen und dann blockweise lesen, indem Sie jeden Block in eine Datei schreiben, damit der Speicher wiederverwendet werden kann.

Wie Sie es geschrieben haben, muss die gesamte Antwort, alle 2 GB, im Speicher sein. Selbst bei einem 64-Bit-System, das die 2-GB-Grenze für ein einzelnes .NET-Objekt erreicht.


Update: einfachere Option. Holen Sie sich WebClient, um die Arbeit für Sie zu erledigen: mit seiner DownloadFile Methode, die die Daten direkt in eine Datei legt.

28

Die WebClient-Klasse ist die für vereinfachte Szenarien. Sobald Sie an einfachen Szenarien vorbeikommen (und Sie haben), müssen Sie ein wenig zurückfallen und WebRequest verwenden.

Mit WebRequest haben Sie Zugriff auf den Antwort-Stream, und Sie können in der Lage sein, darüber zu laufen, ein wenig zu lesen und ein wenig zu schreiben, bis Sie fertig sind.


Beispiel:

public void MyDownloadFile(Uri url, string outputFilePath) 
{ 
    const int BUFFER_SIZE = 16 * 1024; 
    using (var outputFileStream = File.Create(outputFilePath, BUFFER_SIZE)) 
    { 
     var req = WebRequest.Create(url); 
     using (var response = req.GetResponse()) 
     { 
      using (var responseStream = response.GetResponseStream()) 
      { 
       var buffer = new byte[BUFFER_SIZE]; 
       int bytesRead; 
       do 
       { 
        bytesRead = responseStream.Read(buffer, 0, BUFFER_SIZE); 
        outputFileStream.Write(buffer, 0, bytesRead); 
       } while (bytesRead > 0); 
      } 
     } 
    } 
} 

Beachten Sie, dass, wenn WebClient.DownloadFile funktioniert, dann würde ich es die beste Lösung nennen. Ich schrieb das obige, bevor die "DownloadFile" -Antwort veröffentlicht wurde. Ich schrieb es auch viel zu früh am Morgen, so dass ein Körnchen Salz (und Tests) erforderlich sein könnte.

+0

Vielen Dank für Ihre detaillierte Antwort und Code-Schnipsel! Dies ist nützlich in Fällen, wenn ich die Daten verarbeiten will, wie sie ankommen! –

+0

Was ist mit Ausnahmebehandlung oder Wiederholungsmechanismus in diesem Code? Netzwerktrennung usw. –

+0

In den meisten Fällen ist die beste Ausnahmebehandlung überhaupt keine. Wenn Sie sich in einer Situation befinden, in der Ihr Netzwerk sehr unzuverlässig ist, müssen Sie möglicherweise eine Wiederholungslogik hinzufügen. Ich lebe in den Vereinigten Staaten, also bin ich vermutlich durch gute Netzwerkverbindungen verwöhnt. Wenn sie nicht funktionieren, sind die Dinge so schlecht, dass eine Wiederholung nicht sinnvoll ist. –

2

verwenden WebClient.OpenRead einen Stream zurück, verwenden Sie nur lesen, um eine Schleife über den Inhalt, so werden die Daten nicht im Speicher gepuffert, sondern kann in den Blöcken in eine Datei geschrieben werden.

Verwandte Themen