Frage

Ich brauche eine groß Datei (2 GB) über HTTP in einer C # Konsolenanwendung zum Download bereit. Das Problem ist, nach etwa 1,2 GB, die Anwendung läuft aus dem Speicher.

Hier ist der Code verwende ich:

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

Wie Sie sehen können ... Ich lese die Datei direkt in den Speicher. Ich bin mir ziemlich sicher, ich könnte dieses Problem lösen, wenn ich in chunks die Daten wieder von HTTP lesen war und schreiben Sie es in eine Datei auf der Festplatte.

Wie kann ich das tun?

War es hilfreich?

Lösung

Wenn Sie WebClient. Downloadfile es direkt in eine Datei speichern können.

Andere Tipps

Die WebClient-Klasse ist die eine für vereinfachte Szenarien. Sobald Sie mit den einfachen Szenarien erhalten (und Sie haben), werden Sie ein wenig zurück und verwenden WebRequest fallen müssen.

Mit WebRequest, haben Sie Zugriff auf den Antwortstream haben, und Sie werden in einer Schleife über sie in der Lage sein, ein wenig zu lesen und ein bisschen 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 nennen die beste Lösung. Ich schrieb die oben vor der „Downloadfile“ Antwort gepostet. Ich kann es auch viel zu früh am Morgen geschrieben, so ein Salzkorn (und Prüfung) erforderlich sein.

Sie müssen die Antwortstream bekommen und dann in Blöcken gelesen, wobei jeder Block in eine Datei zu schreiben Speicher zu ermöglichen, wiederverwendet werden.

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


Update: einfachere Option. Erhalten Sie WebClient die Arbeit für Sie tun: mit seiner DownloadFile Methode die setzt die Daten direkt in eine Datei.

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

ich so etwas wie dieser verwenden würde

Die Verbindung kann unterbrochen werden, so dass es besser ist, die Datei in kleinen Stücken zum Download bereit.

Akka-Streams können Download-Datei in kleine Stücke von einem System.IO.Stream mit Multithreading helfen. https://getakka.net/articles/intro/what-is-akka. html

Die Download-Verfahren werden die Bytes in die Datei beginnend mit langen fileStart hängen. Wenn die Datei nicht existiert, muss fileStart Wert 0 sein.

using Akka.Actor;
using Akka.IO;
using Akka.Streams;
using Akka.Streams.Dsl;
using Akka.Streams.IO;

private static Sink<ByteString, Task<IOResult>> FileSink(string filename)
{
    return Flow.Create<ByteString>()
        .ToMaterialized(FileIO.ToFile(new FileInfo(filename), FileMode.Append), Keep.Right);
}

private async Task Download(string path, Uri uri, long fileStart)
{
    using (var system = ActorSystem.Create("system"))
    using (var materializer = system.Materializer())
    {
       HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
       request.AddRange(fileStart);

       using (WebResponse response = request.GetResponse())
       {
           Stream stream = response.GetResponseStream();

           await StreamConverters.FromInputStream(() => stream, chunkSize: 1024)
               .RunWith(FileSink(path), materializer);
       }
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top