Разбор большого (20 ГБ) текстового файла с питоном - чтение в 2 строках как 1

Я разбираю файл 20 Гб и выводя строки, которые удовлетворяют определенному условию, на другой файл, однако иногда питон будет читать в двух строках сразу и конкатенировать их.

inputFileHandle = open(inputFileName, 'r')

row = 0

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

Я проверил окончания строки в исходном файле, и они проверяют как линейные каналы (ascii char 10). Вывод строк проблем и их разбор в изолированном режиме, как и ожидалось. Могу ли я использовать ограничение на python? Позиция в файле первой аномалии находится вокруг метки 4 ГБ.

Ответы

Ответ 1

Быстрый поиск по Google для "файлов чтения python размером более 4 ГБ" дал много результатов. См. здесь для такого примера и другой, который берет верх с первого.

Это ошибка в Python.

Теперь объяснение ошибки; это нелегко воспроизвести, потому что это зависит как от внутреннего размера буфера FILE, так и от количества символов, переданных в fread(). В исходном коде Microsoft CRT в open.c есть блок, начинающийся с этого ободряющего комментария "Это трудная часть. Мы обнаружили CR в конце буфера. Мы должны заглянуть вперед, чтобы увидеть, будет ли следующий char LF". Как ни странно, в исходном коде Perl имеется почти точная копия этой функции: http://perl5.git.perl.org/perl.git/blob/4342f4d6df6a7dfa22a470aa21e54a5622c009f3:/win32/win32.c#l3668Проблема заключается в вызове SetFilePointer(), который используется для отступания одной позиции после просмотра; он не сработает, потому что он не может вернуть текущую позицию в 32-битном DWORD. [Исправить легко; Вы видите это?] На этом этапе функция считает, что следующий read() вернет LF, но это произойдет не потому, что указатель файла не был возвращен.

И работа вокруг:

Но обратите внимание, что Python 3.x не влияет (сырые файлы всегда открываются в двоичном режиме, а CRLF-перевод выполняется Python); с 2.7, вы можете использовать io.open().

Ответ 2

Знак 4 ГБ подозрительно близок к максимальному значению, которое может быть сохранено в 32-битном регистре (2 ** 32).

Код, который вы опубликовали, выглядит отлично сам по себе, поэтому я бы заподозрил ошибку в вашей сборке Python.

FWIW, фрагмент будет немного чище, если он использует перечисление:

inputFileHandle = open(inputFileName, 'r')

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