2012-12-06 9 views
12

Ich habe viele große CSV-Dateien (1-10 GB), die ich in Datenbanken importieren. Für jede Datei muss ich die erste Zeile ersetzen, damit ich die Header als Spaltennamen formatieren kann. Meine aktuelle Lösung ist:Schnell erste Zeile der großen Datei ersetzen

using (var reader = new StreamReader(file)) 
{ 
    using (var writer = new StreamWriter(fixed)) 
    { 
     var line = reader.ReadLine(); 
     var fixedLine = parseHeaders(line); 
     writer.WriteLine(fixedLine); 

     while ((line = reader.ReadLine()) != null) 
      writer.WriteLine(line); 
    } 
} 

Was ist ein schneller Weg, nur Zeile 1 zu ersetzen, ohne durch jede andere Zeile dieser riesigen Dateien zu durchlaufen?

+0

Ich würde das wahrscheinlich nur von der Befehlszeile aus tun. 'copy headerfile + csvfile newfile' Sie könnten eine Batchdatei mit allen Dateien erstellen, die geändert werden müssen. (Oh, außer es sieht so aus, als wüsstest du nicht, was die Header sein werden. Wenn nicht, hilft das nicht.) –

+0

Wenn das Tool, das du verwendest, Eingaben über 'stdin' nimmt: statt einer Datei Sie können einen Stream erstellen, der aus den Headern und dem Hauptteil besteht, und ihn bei Bedarf in Ihr Import-Tool einspeisen. z.B. 'cat headerfile bigfile | import_tool' –

+0

Dies ist sehr empfindlich für die Längen von fixedLine und der ersten Zeile. Kann FixedLine jemals größer sein? Könnte Zeile 2 an das Ende der Datei verschoben werden? –

Antwort

7

Wenn Sie garantieren können, dass fixedLine die gleiche Länge (oder weniger) wie line hat, können Sie die Dateien direkt aktualisieren, statt sie zu kopieren.

Wenn nicht, können Sie möglicherweise ein wenig Performance-Verbesserung erhalten, indem die .BaseStream Ihrer StreamReader und StreamWriter und tun große Blockkopien zugreifen (unter Verwendung von, sagen wir, ein 32K-Byte-Puffer), um den Kopiervorgang zu tun, was die zumindest beseitigen Zeit, die damit verbracht wird, jedes Zeichen zu prüfen, um zu sehen, ob es sich um ein Zeilenende-Zeichen handelt, wie es jetzt mit reader.ReadLine() geschieht.

+0

Wenn es weniger wäre, was würdest du mit dem "freien" Raum machen? Pad es mit Leerzeichen? – Jodrell

+0

Wahrscheinlich, aber es hängt vom Format ab. In einer CSV-Datei könnte ich die Header-Elemente zitieren und Leerzeichen nach Kommas hinzufügen. – prprcupofcoffee

+1

+1. @Jodrell, ja, Leerzeichen werden in den meisten Fällen für CSV ignoriert - also wäre es ok, sie für das Padding zu verwenden (ich habe versucht, es in meiner identischen Antwort vorzuschlagen :)).Spaces sind auch für die meisten Codierungen sicher und können bei Bedarf direkt in den Stream als Bytes geschrieben werden. –

6

Die einzige Sache, die es erheblich beschleunigen kann, wenn Sie wirklich ersetzen können erste Zeile. Wenn die erste Zeile nicht länger als die alte Zeile ist, ersetzen Sie die erste Zeile (mit Leerzeichen).

Andernfalls - Sie müssen eine neue Datei erstellen und den Rest nach der ersten Zeile kopieren. Sie können möglicherweise das Kopieren eines Bits optimieren, indem Sie die Puffergrößen/explizite Kopie als binäre/prozuweisende Größe anpassen. Dies ändert jedoch nichts an der Tatsache, dass Sie die gesamte Datei kopieren müssen.

Noch ein Cheat, wenn Sie CSV-Daten trotzdem in DB löschen wollen: Wenn Reihenfolge egal ist, können Sie einige Zeilen von Anfang an lesen, sie durch neue ersetzen und die entfernten Zeilen am Ende der Datei hinzufügen.

Seitennotiz: Wenn das eine einmalige Operation ist, würde ich einfach Dateien kopieren und damit fertig sein ... Debugging-Code, der Daten in die Mitte der Textdatei mit potenziell unterschiedlicher Codierung einfügt, lohnt sich nicht.

Verwandte Themen