2015-04-19 5 views
11

Ich habe Probleme mit etwas Code, der durch eine Reihe von .csvs Schleifen und löscht die letzte Zeile, wenn es nichts darin ist (dh Dateien, die mit dem enden \n Newline-Zeichen)Python 11gb csv im r + Modus nicht öffnen, öffnet im r Modus

Mein Code funktioniert erfolgreich auf allen Dateien außer einer, die mit 11 GB die größte Datei im Verzeichnis ist. Die zweitgrößte Datei ist 4,5 GB.

Die Linie auf nicht ist einfach:

with open(path_str,"r+") as my_file: 

und ich erhalte die folgende Meldung:

IOError: [Errno 22] invalid mode ('r+') or filename: 'F:\\Shapefiles\\ab_premium\\processed_csvs\\a.csv' 

Die path_str I os.file.join create verwenden, Fehler zu vermeiden, und ich versuchte, um die Datei umbenennen a.csv nur um sicherzustellen, dass der Dateiname nicht merkwürdig ist. Dies machte keinen Unterschied.

Noch seltsamer ist die Datei gerne im R-Modus zu öffnen. I.e. der folgende Code funktioniert:

with open(path_str,"r") as my_file: 

ich um die Datei im Lesemodus navigiert haben versucht, und es ist glücklich Zeichen am Anfang, Ende und in der Mitte der Datei zu lesen.

Kennt jemand irgendwelche Einschränkungen der Dateigröße, mit der Python umgehen kann oder warum ich diesen Fehler bekomme? Ich bin auf Windows 7 64bit und habe 16 GB RAM.

+3

Es muss aufgrund Textmodus sein. Funktioniert 'r + b'? –

+0

Programmiert Ihr Programm irgendetwas anderes mit diesen CSV-Dateien, oder entfernt es einfach die überflüssigen nachlaufenden Zeilenumbrüche? –

+0

@ PM2Ring Danke. Ja - es entfernt nur die abschließenden Zeilenumbrüche. Wenn Sie eine einfachere Lösung für dieses Problem haben, ich bin ganz Ohr :-) Hier ist der Code: https://gist.github.com/RobinL/9895b764ca3ce61c8e37. Ich habe in der Frage nicht nach einer alternativen Lösung gefragt, weil ich neugierig bin, um die Ursache dieses Problems herauszufinden. – RobinL

Antwort

19

Der Standard-E/A-Stapel in Python 2 ist über CRT FILE Streams geschichtet. Unter Windows sind diese auf einer POSIX-Emulations-API aufgebaut, die Dateideskriptoren verwendet (die wiederum über die Benutzermodus-Windows-API geschichtet sind, die sich über das Kernelmodus-I/O-System erstreckt, das wiederum ein tiefschichtiges System ist basierend auf E/A-Anfrage-Paketen, die Hardware ist irgendwo da unten ...). Wenn Sie in der POSIX-Ebene eine Datei mit dem Modus _O_RDWR | _O_TEXT (wie in "r +") öffnen, müssen Sie das Ende der Datei suchen, um STRG + Z zu entfernen, falls vorhanden. Hier ist ein Zitat aus der CRT fopen Dokumentation:

Öffnen im Text (übersetzt) ​​-Modus. In diesem Modus wird STRG + Z als ein Dateiende-Zeichen bei der Eingabe interpretiert. In Dateien geöffnet zum Lesen/Schreiben mit "a +", fopen prüft auf ein STRG + Z am Ende der Datei und entfernt es, wenn möglich. Dies geschieht, weil die Verwendung von fseek und ftell zu in einer Datei, die mit STRG + Z endet, dazu führen kann, dass sich fseek falsch am Ende der Datei verhält.

Das Problem hierbei ist, dass die obige Prüfung die 32-Bit ruft _lseek (bedenken, dass sizeof long 4 Bytes auf 64-Bit-Windows ist, im Gegensatz zu den meisten anderen 64-Bit-Plattformen), statt _lseeki64. Offensichtlich schlägt dies für eine 11-GB-Datei fehl. Insbesondere schlägt SetFilePointer fehl, da es mit einem NULL-Wert für lpDistanceToMoveHigh aufgerufen wird. Hier ist der Rückgabewert und LastErrorValue für letztere Aufruf:

0:000> kc 2 
Call Site 
KERNELBASE!SetFilePointer 
MSVCR90!lseek_nolock 

0:000> r rax      
rax=00000000ffffffff 

0:000> dt _TEB @$teb LastErrorValue 
ntdll!_TEB 
    +0x068 LastErrorValue : 0x57 

Der Fehlercode 0x57 ERROR_INVALID_PARAMETER ist. Dies bezieht sich auf lpDistanceToMoveHigh wird NULL beim Versuch, vom Ende einer großen Datei suchen.

Um dieses Problem mit CRT FILE Streams umzugehen, empfehle ich, die Datei mit io.open stattdessen zu öffnen. Dies ist eine zurückportierte Implementierung des I/O-Stacks von Python 3. Es öffnet immer Dateien im binären Rohmodus (_O_BINARY) und implementiert eigene Puffer- und Textmodus-Layer über der Rohschicht.

>>> import io      
>>> f = io.open('a.csv', 'r+') 
>>> f  
<_io.TextIOWrapper name='a.csv' encoding='cp1252'> 
>>> f.buffer 
<_io.BufferedRandom name='a.csv'> 
>>> f.buffer.raw 
<_io.FileIO name='a.csv' mode='rb+'> 
>>> f.seek(0, os.SEEK_END) 
11811160064L 
+0

Endlich jemand, der weiß, was wirklich los ist. :) Ich habe nicht einmal _think_ über diese lästigen Strg-Z ... –

+0

Dies ist eine brillante Antwort - genau die Informationen, die ich habe versucht, Google nach ohne Erfolg zu suchen. Vielen Dank. – RobinL