Эффективно анализируете большой текстовый файл в Python?

У меня есть ряд больших плоских текстовых файлов, которые мне нужно проанализировать, чтобы вставить в базу данных SQL. Каждая запись занимает несколько строк и состоит примерно из сотни полей фиксированной длины. Я пытаюсь понять, как эффективно их анализировать, не загружая весь файл в память.

Каждая запись начинается с цифры «1» в качестве первого символа в новой строке (хотя не каждая строка, начинающаяся с «1», является новой записью) и заканчивается несколькими строками позже серией из 20 пробелов. Хотя каждое поле имеет фиксированную ширину, каждая запись имеет переменную длину, поскольку она может содержать или не содержать несколько необязательных полей. Поэтому я использовал "...20 spaces...\n1" в качестве разделителя записей.

Я пытался работать с чем-то вроде этого, чтобы обрабатывать 1 КБ за раз:

def read_in_chunks(file_object, chunk_size):
    while True:
        data = file_object.read(chunk_size)
        if not data:
            break
        yield data

file = open('test.txt')
for piece in read_in_chunks(file, chunk_size=1024):
   # Do stuff

Однако проблема, с которой я сталкиваюсь, заключается в том, что одна запись охватывает несколько фрагментов. Я упускаю из виду очевидный шаблон проектирования? Эта проблема может показаться несколько распространенной. Спасибо!


person jamieb    schedule 15.11.2011    source источник
comment
хорошо, я перечитал вопрос ... почему бы не проанализировать файл один раз, просто как сквозное чтение, чтобы получить конец позиций записи всех записей ... затем вернуться, передав эти значения размеру вашего фрагмента   -  person RobotHumans    schedule 15.11.2011
comment
@aking1012: Спасибо. Это подход, с которым я работаю с тех пор, как написал этот вопрос. Однако чтение по байту за раз занимает вечность, а чтение более одного байта за раз по-прежнему оставляет меня с проблемой данных, охватывающих несколько фрагментов. Я уверен, что прямо передо мной есть очевидное решение.   -  person jamieb    schedule 15.11.2011
comment
да, если вы читаете два куска за раз... тогда проблема решена. в C это было бы реализовано как кольцевой буфер. я не видел быстрой реализации циклического буфера, кроме чтения двух фрагментов и перетаскивания его для python. если вы используете два фрагмента одновременно, использование rstrip/lstrip и получение разницы в размере может быть эффективным ... но я не тестировал его под нагрузкой.   -  person RobotHumans    schedule 15.11.2011
comment
Два фрагмента также не будут работать, если запись может быть длиннее одного фрагмента. Запись размером 1026 байт, начинающаяся с последнего байта фрагмента, будет полностью охватывать следующий фрагмент, а также первый байт третьего фрагмента. Но читать файл кусками по 1024 байта в любом случае глупо, если только в вашей системе очень мало памяти.   -  person rob mayoff    schedule 15.11.2011
comment
@robmayoff, если вы ищете только точки завершения ... размер записи больше не имеет значения ... размер терминатора имеет значение. затем вы настраиваете размер своего фрагмента на размер памяти. просто мое мнение. о том, насколько велик файл, когда я слышу, что большой плоский текстовый файл переносится на sql, я думаю, что финансовое учреждение с файлом на много ГБ   -  person RobotHumans    schedule 15.11.2011
comment
Ясно... но если его размер много ГБ, зачем мне читать весь файл дважды, чтобы загрузить его?   -  person rob mayoff    schedule 15.11.2011


Ответы (1)


def recordsFromFile(inputFile):
    record = ''
    terminator = ' ' * 20
    for line in inputFile:
        if line.startswith('1') and record.endswith(terminator):
            yield record
            record = ''
        record += line
    yield record

inputFile = open('test.txt')
for record in recordsFromFile(inputFile):
    # Do stuff

Кстати, file — это встроенная функция. Это плохой стиль, чтобы изменить его значение.

person rob mayoff    schedule 15.11.2011
comment
немного более эффективно создавать строки, используя списки, за которыми следует ''.join() в конце. - person ben w; 15.11.2011
comment
мне это нравится, но разве это не загружает в память огромное количество данных, если это большой файл? - person RobotHumans; 15.11.2011
comment
Я не думаю, что это так. Как вы думаете, почему? Будет ли это проблемой, если это произойдет? Насколько велик входной файл? - person rob mayoff; 15.11.2011
comment
Он будет загружать только одну запись в память. Итераторы файлов Python чрезвычайно просты в использовании и относительно эффективны, особенно в отношении памяти. - person fandingo; 15.11.2011
comment
Я люблю yield, он делает вещи такими эффективными и простыми - person juliomalegria; 15.11.2011
comment
Я не думаю, что это плохой стиль — назначать file. я считаю file - person Dietrich Epp; 15.11.2011