Ефективно анализиране на голям текстов файл в Python?

Имам поредица от големи, плоски текстови файлове, които трябва да анализирам, за да вмъкна в SQL база данни. Всеки запис обхваща няколко реда и се състои от около сто полета с фиксирана дължина. Опитвам се да разбера как ефективно да ги анализирам, без да зареждам целия файл в паметта.

Всеки запис започва с цифра "1" като първи знак на нов ред (въпреки че не всеки ред, който започва с "1", е нов запис) и завършва много редове по-късно с поредица от 20 интервала. Докато всяко поле е с фиксирана ширина, всеки запис е с променлива дължина, защото може или не може да съдържа няколко незадължителни полета. Така че използвах "...20 spaces...\n1" като разделител на запис.

Опитвам се да работя с нещо подобно, за да обработвам 1 kb наведнъж:

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, мисля, че финансова институция с файл с много GB   -  person RobotHumans    schedule 15.11.2011
comment
Разбирам... но ако е с размер много GB, защо ще искам да чета целия файл два пъти, за да го заредя?   -  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