2012-04-19 7 views
15

Ich Parsing eine 20 GB-Datei und Ausgabe Zeilen, die eine bestimmte Bedingung zu einer anderen Datei erfüllen, aber gelegentlich Python liest in 2 Zeilen gleichzeitig und verketten Sie.Parsing große (20GB) Textdatei mit Python - Lesen in 2 Zeilen als 1

Ich habe die Zeilenenden in der Quelldatei überprüft und sie als Zeilenvorschübe auschecken (ASCII Char 10). Das Auspacken der Problemzeilen und das separate Analysieren dieser Probleme funktioniert wie erwartet. Triff ich hier eine Python-Beschränkung? Die Position in der Datei der ersten Anomalie liegt um die 4 GB-Marke.

+0

tritt die erste Anomalie immer konsistent bei der gleichen Zeilenanzahl auf? Außerdem ist 'lstIgnoredRows' eine Liste, wie groß wächst das? Ich frage mich, was passiert, wenn Sie nur die Zeilen gespeichert haben, die Sie interessieren, und nichts mit den Zeilen tun, die Sie ignorieren möchten. – Levon

+1

Vielleicht könnten Sie versuchen, kleinere Teile der Datei gleichzeitig mit einer faulen Methode zu lesen, ähnlich dieser Frage? Probieren Sie es aus http://stackoverflow.com/questions/519633/lazy-method-for-reading-big-file-in-python – prrao

+0

Es passiert jedes Mal die gleiche Zeile. lstIgnoredRows kann auf ein paar tausend Elemente anwachsen. – James

Antwort

23

schnelle Google-Suche nach „Python Lesen von Dateien größer als 4 GB“ ergab viele viele Ergebnisse. Siehe here for such an exampleand another one which takes over from the first.

Es ist ein Fehler in Python.

Jetzt die Erklärung des Fehlers; es ist nicht einfach zu reproduzieren, da es sowohl von der internen FILE Puffergröße als auch von der Anzahl der an fread() übergebenen Zeichen abhängt. Im Microsoft CRT-Quellcode, in open.c, gibt es einen Block, der mit diesem ermutigenden Kommentar beginnt: "Das ist der schwierige Teil. Wir haben am Ende des Puffers eine CR gefunden. Wir müssen nachsehen, ob das nächste Zeichen ein LF ist . " Seltsamerweise gibt es eine fast exakte Kopie dieser Funktion im Perl-Quellcode: http://perl5.git.perl.org/perl.git/blob/4342f4d6df6a7dfa22a470aa21e54a5622c009f3:/win32/win32.c#l3668 Das Problem ist in den Aufruf von SetFilePointer(), verwendet, um eine Position nach dem Lookahead zurückzutreten; Es wird fehlschlagen, da es die aktuelle Position in einem 32-Bit-DWORD nicht zurückgeben kann. [Die Lösung ist einfach; Siehst du es?] An dieser Stelle denkt die Funktion, dass das nächste read() das LF zurückgeben wird, aber es wird nicht, weil der Dateizeiger nicht zurück verschoben wurde.

Und die Behelfslösung:

Aber beachten Sie, dass Python 3.x ist nicht betroffen (Raw-Dateien werden im Binär-Modus immer geöffnet und CRLF Übersetzung wird von Python getan); Mit 2.7 können Sie io.open() verwenden.

+1

Öffnen der Datei im Binärmodus behoben dieses Problem.Danke für Ihre Hilfe open (inputFileName, 'rb') – James

+0

Öffnen im Binärmodus löste es für mich auch, das ist ein Lebensretter! – tlamadon

7

Die 4 GB-Marke ist verdächtig nahe dem Maximalwert, der in einem 32-Bit-Register (2 ** 32) gespeichert werden kann.

Der Code, den Sie gepostet haben, sieht von selbst gut aus, also würde ich einen Fehler in Ihrem Python-Build vermuten.

FWIW, würde das Snippet ein wenig sauberer sein, wenn es verwendet aufzählen:

inputFileHandle = open(inputFileName, 'r') 

for row, line in enumerate(inputFileHandle): 
    if line_meets_condition: 
     outputFileHandle.write(line) 
    else: 
     lstIgnoredRows.append(row)