2015-04-19 14 views
11

Ho problemi con un codice che scorre in un gruppo di .csv e cancella la riga finale se non c'è nulla in esso (cioè file che terminano con \n carattere newline)Python non riesce ad aprire 11gb csv in modalità r + ma si apre in modalità r

Il mio codice funziona correttamente su tutti i file tranne uno, che è il file più grande nella directory a 11 GB. Il secondo file più grande è 4,5 GB.

La linea non riesce a è semplicemente:

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

e ottengo il seguente messaggio:

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

Il path_str creo usando os.file.join per evitare errori, e ho provato rinominando il file di a.csv solo per assicurarsi che non ci fosse qualcosa di strano con il nome del file. Questo non ha fatto differenza.

Ancora più strano, il file è felice di aprire in modalità r. Cioè il seguente codice funziona bene:

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

Ho provato a navigare in tutto il file in modalità di lettura, ed è felice di leggere i caratteri all'inizio, fine, e nel mezzo del file.

Qualcuno sa di limiti sulla dimensione del file che Python può gestire o perché si potrebbe ricevere questo errore? Sono su Windows 7 a 64 bit e ho 16 GB di RAM.

+3

Deve essere dovuto alla modalità testo. 'R + b' funziona? –

+0

Il tuo programma sta facendo qualcos'altro con questi file csv, o semplicemente rimuovendo le newline finali in eccesso? –

+0

@ PM2Ring Grazie. Sì, sta solo rimuovendo i newline finali. Se hai una soluzione più facile a questo problema, sono tutto orecchie :-) Ecco il codice: https://gist.github.com/RobinL/9895b764ca3ce61c8e37. Non ho chiesto una soluzione alternativa nella domanda perché sono curioso di scoprire la fonte di questo problema. – RobinL

risposta

19

Lo stack I/O predefinito in Python 2 è sovrapposto ai flussi CRT FILE. Su Windows questi sono costruiti su un'API di emulazione POSIX che utilizza i descrittori di file (che a loro volta sono sovrapposti all'API Windows in modalità utente, che è sovrapposta al sistema I/O in modalità kernel, che a sua volta è un sistema a strati profondi basato su pacchetti di richiesta I/O, l'hardware è laggiù da qualche parte ...). Nel livello POSIX, aprendo un file con la modalità _O_RDWR | _O_TEXT (come in "r +"), è necessario cercare fino alla fine del file per rimuovere CTRL + Z, se presente. Ecco una citazione dalla documentazione fopen del CRT:

Apri in modalità testo (traduzione). In questa modalità, CTRL + Z viene interpretato come un carattere di fine file in input. Nei file aperti per lettura/scrittura con "a +", fopen controlla un CTRL + Z alla fine del file e lo rimuove, se possibile. Ciò avviene perché l'uso di fseek e ftell per lo spostamento di all'interno di un file che termina con CTRL + Z, può causare che fseek si comporti in modo improprio vicino alla fine del file.

Il problema qui è che il controllo di cui sopra definisce 32 bit _lseek (si tenga presente che sizeof long è di 4 byte su Windows a 64 bit, a differenza delle altre piattaforme a 64 bit), invece di _lseeki64. Ovviamente questo non riesce per un file da 11 GB. In particolare, SetFilePointer non riesce perché viene chiamato con un valore NULL per lpDistanceToMoveHigh. Ecco il valore di ritorno e LastErrorValue per la seconda chiamata:

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 

Il codice di errore 0x57 è ERROR_INVALID_PARAMETER. Si riferisce a lpDistanceToMoveHigh per il NULL quando si cerca di cercare dalla fine di un file di grandi dimensioni.

Per ovviare a questo problema con gli stream CRT FILE, è consigliabile aprire il file utilizzando io.open. Questa è un'implementazione backported dello stack I/O di Python 3. Apre sempre i file in modalità binaria grezza (_O_BINARY) e implementa i propri livelli di buffering e di modalità testo nella parte superiore del livello grezzo.

>>> 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

Finalmente qualcuno che sa cosa sta succedendo veramente. :) Non ho nemmeno pensato a quel fastidioso Ctrl-Z ... –

+0

Questa è una risposta brillante - esattamente l'informazione che stavo cercando di cercare su Google senza successo. Grazie. – RobinL

Problemi correlati