Ich arbeite mit einigen Multi-Gigabyte-Textdateien und möchte mit PowerShell Stream-Verarbeitung für sie durchführen. Es ist ganz einfach, jede Zeile zu analysieren, einige Daten abzurufen und sie dann in einer Datenbank zu speichern.
Leider get-content | %{ whatever($_) }
scheint der gesamte Satz von Zeilen in dieser Phase der Pipe im Speicher zu bleiben. Es ist auch überraschend langsam und es dauert sehr lange, alles tatsächlich einzulesen.
Meine Frage besteht also aus zwei Teilen:
- Wie kann ich dafür sorgen, dass der Stream zeilenweise verarbeitet wird und nicht das gesamte Objekt im Speicher gepuffert wird? Ich möchte vermeiden, mehrere GB RAM für diesen Zweck zu verbrauchen.
- Wie kann ich es schneller laufen lassen? PowerShell, das über a iteriert,
get-content
scheint 100-mal langsamer zu sein als ein C # -Skript.
Ich hoffe, ich mache hier etwas Dummes, wie das Fehlen eines -LineBufferSize
Parameters oder so ...
powershell
stream
scobi
quelle
quelle
get-content
, setzen Sie -ReadCount auf 512. Beachten Sie, dass $ _ im Foreach zu diesem Zeitpunkt ein Array von Zeichenfolgen ist.Get-Content
einer Variablen zuzuweisen, da dadurch die gesamte Datei in den Speicher geladen wird. StandardmäßigGet-Content
verarbeitet die Datei in einer Pipleline zeilenweise. Solange Sie die Ergebnisse nicht akkumulieren oder ein intern akkumuliertes Cmdlet verwenden (wie Sort-Object und Group-Object), sollte der Speicher-Hit nicht zu schlecht sein. Foreach-Object (%) ist eine sichere Methode, um jede Zeile einzeln zu verarbeiten.get-content | % -End { }
es sich beschwert , wenn Sie versuchen, es zu verwenden , weil Sie keinen Prozessblock angegeben haben. Daher kann standardmäßig nicht -End verwendet werden, sondern standardmäßig -Process. Und versuchen Sie zu1..5 | % -process { } -end { 'q' }
sehen, dass dergc | % { $_ }
Endblock nur einmal vorkommt. Das Übliche würde nicht funktionieren, wenn der Skriptblock standardmäßig -End ...Antworten:
Wenn Sie wirklich an Textdateien mit mehreren Gigabyte arbeiten möchten, verwenden Sie PowerShell nicht. Selbst wenn Sie einen Weg finden, es schneller zu lesen, wird die Verarbeitung einer großen Anzahl von Zeilen in PowerShell ohnehin langsam sein, und Sie können dies nicht vermeiden. Selbst einfache Schleifen sind teuer, sagen wir für 10 Millionen Iterationen (in Ihrem Fall ziemlich real), die wir haben:
UPDATE: Wenn Sie immer noch keine Angst haben, versuchen Sie, den .NET-Reader zu verwenden:
UPDATE 2
Es gibt Kommentare zu möglicherweise besserem / kürzerem Code. Es ist nichts falsch mit dem Originalcode
for
und es ist kein Pseudocode. Die kürzere (kürzeste?) Variante der Leseschleife ist jedochquelle
do { $line = $reader.ReadLine(); $line } while ($line -neq $null)
for ( $line = $reader.ReadLine(); $line -ne $null; $line = $reader.ReadLine() ) { $line }
while($null -ne ($line = $read.ReadLine())) {$line}
. Aber das Thema handelt nicht wirklich von solchen Dingen.System.IO.File.ReadLines()
ist perfekt für dieses Szenario. Es gibt alle Zeilen einer Datei zurück, aber Sie können sofort mit dem Durchlaufen der Zeilen beginnen, sodass nicht der gesamte Inhalt im Speicher gespeichert werden muss.Benötigt .NET 4.0 oder höher.
http://msdn.microsoft.com/en-us/library/dd383503.aspx
quelle
Wenn Sie PowerShell verwenden möchten, lesen Sie den folgenden Code.
quelle
Get-Content
es bei großen Dateien sehr langsam ist.