2012-04-19 17 views
15

Estoy analizando un archivo de 20Gb y enviando líneas que cumplen una condición determinada a otro archivo, sin embargo ocasionalmente python leerá en 2 líneas a la vez y concatenará ellos.Analizando un archivo de texto grande (20GB) con python - leyendo en 2 líneas como 1

inputFileHandle = open(inputFileName, 'r') 

row = 0 

for line in inputFileHandle: 
    row = row + 1 
    if line_meets_condition: 
     outputFileHandle.write(line) 
    else: 
     lstIgnoredRows.append(row) 

He comprobado las terminaciones de línea en el archivo de origen y se comprueban como alimentaciones de línea (ascii char 10). Sacar las filas del problema y analizarlas en forma aislada funciona como se esperaba. ¿Estoy golpeando alguna limitación python aquí? La posición en el archivo de la primera anomalía está alrededor de la marca de 4 GB.

+0

¿La primera anomalía siempre ocurre de manera consistente en el mismo recuento de líneas? Además, es 'lstIgnoredRows' una lista, ¿qué tan grande crece? Me pregunto qué pasaría si acaba de guardar las líneas que le interesan en el archivo de salida y no hizo nada con las líneas que quería ignorar. – Levon

+1

Tal vez podrías intentar leer trozos más pequeños del archivo a la vez usando un método lento, similar a esta pregunta? Pruébalo http://stackoverflow.com/questions/519633/lazy-method-for-reading-big-file-in-python – prrao

+0

Sucede en el mismo recuento de líneas cada vez. lstIgnoredRows puede crecer a unos pocos miles de elementos. – James

Respuesta

23

rápida búsqueda en Google de "archivos de lectura pitón más de 4 GB" dio muchos muchos resultados. Ver here for such an exampleand another one which takes over from the first.

Es un error en Python.

Ahora, la explicación del error; no es fácil de reproducir porque depende tanto del tamaño del búfer del ARCHIVO interno como del número de caracteres que se pasan a fread(). En el código fuente de Microsoft CRT, en open.c, hay un bloqueo que comienza con este alentador comentario: "Esta es la parte difícil. Encontramos un CR al final del buffer. Debemos mirar hacia adelante para ver si el siguiente char es un LF " Curiosamente, hay una copia casi exacta de esta función en el código fuente de Perl: http://perl5.git.perl.org/perl.git/blob/4342f4d6df6a7dfa22a470aa21e54a5622c009f3:/win32/win32.c#l3668 El problema está en la llamada a SetFilePointer(), utilizada para retroceder una posición después de la búsqueda anticipada; fallará porque no puede devolver la posición actual en un DWORD de 32 bits. [La solución es fácil; ¿lo ves?] En este punto, la función piensa que la próxima lectura() devolverá el LF, pero no lo hará porque el puntero del archivo no se movió hacia atrás.

Y el trabajo en torno a:

Pero en cuenta que Python 3.x no se ve afectada (archivos RAW siempre se abren en modo binario y traducción CRLF se realiza mediante Python); con 2.7, puede usar io.open().

+1

Al abrir el archivo en modo binario solucionado este problema.Gracias por su ayuda open (inputFileName, 'rb') – James

+0

abriendo en modo binario también lo resolvió para mí, ¡esto es un salvavidas! – tlamadon

7

La marca de 4 GB sospechosamente está cerca del valor máximo que se puede almacenar en un registro de 32 bits (2 ** 32).

El código que ha publicado se ve bien por sí mismo, por lo que sospecho que hay un error en su compilación de Python.

Fwiw, el fragmento sería un poco más limpio si se utiliza enumerar:

inputFileHandle = open(inputFileName, 'r') 

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