Wie schreibt man super-schnelle Datei-streaming von code in C#?
Habe ich auf split eine große Datei in viele kleinere Dateien. Jeder der Ziel-Dateien ist definiert durch eine offset-und length die Anzahl der bytes. Ich bin mit dem folgenden code:
private void copy(string srcFile, string dstFile, int offset, int length)
{
BinaryReader reader = new BinaryReader(File.OpenRead(srcFile));
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
byte[] buffer = reader.ReadBytes(length);
BinaryWriter writer = new BinaryWriter(File.OpenWrite(dstFile));
writer.Write(buffer);
}
Bedenkt, dass ich zu rufen Sie diese Funktion über 100.000 mal, es ist bemerkenswert langsam.
- Gibt es eine Möglichkeit, um die Autorin direkt an die Leser? (Das heißt, ohne tatsächlich das laden der Inhalte in den Puffer im Arbeitsspeicher.)
InformationsquelleAutor der Frage ala | 2009-06-05
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich glaube nicht, dass es etwas gibt, innerhalb .NET ermöglicht das kopieren eines Abschnitts von einer Datei ohne Zwischenspeicherung im Arbeitsspeicher. Allerdings fällt mir auf, dass es ineffizient ist sowieso, wie es braucht, um öffnen Sie die input-Datei und suchen Sie viele Male. Wenn Sie nur Aufteilung der Datei, warum nicht öffnen der Eingabedatei einmal, und dann schreiben Sie einfach etwas wie:
Dieser hat eine kleine Ineffizienz bei der Schaffung einer Puffer bei jedem Aufruf einer - möglicherweise möchten Sie erstellen den Puffer einmal und pass, die in der Methode als auch:
Beachten Sie, dass diese auch schließt den Ausgabe-stream (durch die using-Anweisung), die Ihre ursprüngliche code nicht.
Der wichtige Punkt ist, dass das Betriebssystem die Datei-Pufferung effizienter, weil Sie die Wiederverwendung der gleichen input-stream, anstelle von erneuten öffnen der Datei am Anfang und dann suchen.
Ich denke werde es deutlich schneller, aber natürlich werden Sie brauchen, um zu versuchen, um zu sehen,...
Dieser übernimmt die zusammenhängenden Stücke, natürlich. Wenn Sie brauchen, um zu überspringen bits der Datei, können Sie tun, aus außerhalb der Methode. Auch, wenn Sie das schreiben von sehr kleinen Dateien, möchten Sie vielleicht, um die Optimierung für die situation zu - der einfachste Weg, dies zu tun wäre wahrscheinlich die Einführung einer
BufferedStream
Verpackung der input-stream.InformationsquelleAutor der Antwort Jon Skeet
Der Schnellste Weg, das zu tun, Datei-I/O von C# ist die Verwendung der Windows ReadFile und WriteFile Funktionen. Ich habe geschrieben eine C# - Klasse, kapselt diese Funktion als auch als benchmarking-Programm, das sich in verschiedenen I/O-Methoden, einschließlich der BinaryReader und BinaryWriter. Siehe meinen blog-post an:
http://designingefficientsoftware.wordpress.com/2011/03/03/efficient-file-io-from-csharp/
InformationsquelleAutor der Antwort Bob Bryan
Wie groß ist
length
? Sie können besser tun, um zu re-verwenden Sie eine Feste Größe (nicht allzu großes, aber nicht obszön) Puffer, und vergessenBinaryReader
... verwenden Sie einfachStream.Read
undStream.Write
.(edit) so etwas wie:
InformationsquelleAutor der Antwort Marc Gravell
Sollten Sie sich nicht wieder öffnen der Quell-Datei jedes mal, wenn Sie tun, eine Kopie, besser öffnen Sie es einmal und übergeben Sie die resultierende BinaryReader, um die kopieren-Funktion. Auch könnte es helfen, wenn Sie, um Ihre sucht, damit Sie nicht machen große Sprünge in der Datei.
Wenn die Länge nicht allzu groß ist, können Sie auch versuchen, die Gruppe ein paar Kopier-Anrufe durch die Gruppierung von offsets, die in der Nähe zueinander und dem Lesen der ganze block, den Sie brauchen, für Sie, zum Beispiel:
können gruppiert werden, um ein Lesen:
Dann müssen Sie nur auf "suchen" in Ihrem Puffer, und können schreiben, die drei neuen Dateien von dort aus, ohne noch einmal zu Lesen.
InformationsquelleAutor der Antwort schnaader
Haben Sie sich überlegt mit der CCR, da Sie schriftlich sind separate Dateien, die Sie tun können, alles parallel (Lesen und schreiben) und der CCR-macht es sehr einfach, dies zu tun.
Dieser code posten offsets zu einem CCR-port was bewirkt, dass ein Thread erstellt werden, um den code auszuführen, der in der Split-Methode. Dies bewirkt, dass Sie, die Datei zu öffnen mehrere Male, aber beseitigt die Notwendigkeit für die Synchronisation. Sie können machen Sie mehr Speicher effizient, aber Sie müssen zu opfern Geschwindigkeit.
InformationsquelleAutor der Antwort SpaceghostAli
Das erste, was ich empfehlen würde, ist eine Messung. Wo verlieren Sie Ihre Zeit? Ist es im Lesen oder schreiben?
Über 100.000 Zugriffe (Summe der Zeiten):
Wie viel Zeit wird für die Zuordnung der buffer-array?
Wie viel Zeit wird damit verbracht, die Datei öffnen für Lesen (es ist die gleiche Datei jedes mal?)
Wie viel Zeit verbringen Sie im lese-und schreib-Operationen?
Wenn Sie nicht tun, jede Art von transformation auf die Datei, Sie benötigen ein BinaryWriter, oder Sie können verwenden Sie ein filestream für schreibt? (probieren Sie es aus, tun Sie das gleiche Ergebnis? bedeutet es, Zeit zu sparen?)
InformationsquelleAutor der Antwort JMarsch
Verwendung von FileStream - + StreamWriter ich weiß, es ist möglich erstellen Sie riesige Dateien in wenig Zeit (weniger als 1 min 30 Sekunden). Ich erzeugt drei Dateien mit insgesamt 700+ MB von einer Datei mit diesem Technik.
Ihre primäre problem mit dem code, die Sie verwenden ist, dass Sie das öffnen einer Datei jedes mal. , Erstellen von Datei-I/O-overhead.
Wenn Sie wusste, dass die Namen der Dateien, die Sie würde die Generierung vor der Zeit, können Sie extrahieren Sie die Datei.OpenWrite in eine separate Methode; es wird die Geschwindigkeit erhöhen. Ohne zu sehen, den code, der bestimmt, wie Sie die Aufteilung der Dateien, ich glaube nicht, können Sie viel schneller.
InformationsquelleAutor der Antwort mcauthorn
Niemand schlägt threading? Schreiben Sie die kleineren Dateien sieht aus wie text-Buch-Beispiel von wo-threads sind sinnvoll. Richten Sie eine Reihe von threads zu erstellen, die kleineren Dateien. auf diese Weise erstellen, können Sie Sie alle parallel und Sie brauchen nicht zu warten, für jede zu beenden. Meine Vermutung ist, dass die Erstellung von Dateien(disk Betrieb) dauert viel länger als das aufteilen der Daten. und natürlich sollten Sie überprüfen, zuerst, daß eine sequentielle Ansatz ist nicht ausreichend.
InformationsquelleAutor der Antwort TheSean
(Für zukünftige Referenz.)
Wahrscheinlich der Schnellste Weg, dies zu tun wäre, um memory-mapped-Dateien (also vor allem das kopieren von Speicher, und die OS-Behandlung die Datei liest/schreibt über seine paging - /Speicher-management).
Memory-Mapped-Dateien sind in verwaltetem code unterstützt .NET 4.0.
Aber wie gesagt, Sie brauchen ein Profil, und erwarten, dass der switch von native-code für maximale Leistung.
InformationsquelleAutor der Antwort Richard