2016-08-25 4 views
3

Следующий код будет лениво распечатывать содержимое текстового файла по строкам, причем каждая печать останавливается на '/ n'.Python Lazy Загрузка

with open('eggs.txt', 'rb') as file: 
     for line in file: 
      print line 

Есть ли какая-либо конфигурация для ленивой печати содержимого текстового файла, при каждой остановке печати в ','?

(или любой другой символ/строка)

Я спрашиваю это потому, что я пытаюсь прочитать файл, который содержит один единственный 2,9 Гб длинную линию, разделенные запятыми.

PS. Мой вопрос иначе, чем это: Read large text files in Python, line by line without loading it in to memory Я спрашиваю, как сделать остановку на других, чем переводы строк символов («\ п»)

+2

Почему это лениво? –

+1

@grael Это совсем не актуально. – taleinat

+0

Функция 'split()' не выполняет работу так же хорошо? –

ответ

2

Я не думаю, что есть встроенный способ для достижения этой цели. Вам нужно будет использовать file.read(block_size), чтобы прочитать блок файла по блоку, разделить каждый блок запятыми и воссоединиться с строками, которые вручную пересекают границы блоков.

Обратите внимание, что вы все еще можете не использовать память, если вы не сталкиваетесь с запятой в течение длительного времени. (Та же самая проблема с чтением файла построчно, при столкновении с очень длинной строки.)

Вот пример реализации:

def split_file(file, sep=",", block_size=16384): 
    last_fragment = "" 
    while True: 
     block = file.read(block_size) 
     if not block: 
      break 
     block_fragments = iter(block.split(sep)) 
     last_fragment += next(block_fragments) 
     for fragment in block_fragments: 
      yield last_fragment 
      last_fragment = fragment 
    yield last_fragment 
+0

С точки зрения скорости, как вы думаете, было бы лучше Если бы я предварительно обработал файл liko: 'g = open (файл," w "). Next(). Replace (", ","/n ")' ; g2 = open (файл, «w»). write (g); g = None а затем ленивая загрузка его обычным способом? – RetroCode

+0

То, что я сделал, временно загрузило файл в память, заменив запятые на «\ n», а затем установив файл равным None, чтобы освободить память, потому что если файл остается в памяти, тогда я испытываю медленное время выполнения (перехват), когда выполняя дальнейшие операции. – RetroCode

+0

@RetroCode Загрузка всего файла в память - это то, чего вы хотели избежать. Я не думаю, что это улучшит производительность, нет. (Примечание: для развязывания имени используйте 'del name' вместо назначения' None'.) –

1

Следующий ответ можно считать ленивым, так как это чтение файла характер, в то время:

def commaBreak(filename): 
    word = "" 
    with open(filename) as f: 
     while True: 
      char = f.read(1) 
      if not char: 
       print "End of file" 
       yield word 
       break 
      elif char == ',': 
       yield word 
       word = "" 
      else: 
       word += char 

Вы можете сделать что-то подобное с большим числом charachters, например, 1000, читать в то время.

+0

Это все еще загружает весь файл в память, а именно в список 'wordList'. –

+0

@SvenMarnach, Он загрузил бы один чарчатер за раз, пока память не будет полной, верно? –

+0

Это незначительная нить. Вы должны поместить этот код в функцию генератора и получить каждое найденное слово вместо добавления в список, чтобы потребитель мог потреблять биты итеративно, без необходимости сразу загружать их все в память. Основная проблема с этим подходом заключается в том, что он будет довольно медленным. –

-1
with open('eggs.txt', 'rb') as file: 
for line in file: 
    str_line = str(line) 
    words = str_line.split(', ') 
    for word in words: 
     print(word) 

Я не совсем уверен, знаю ли я, что вы просите, что-то вроде этого, что вы имеете в виду?

+0

Это не сработает, поскольку он не может прочитать строку длиной 2.9 ГБ, разделенную запятыми, с 'for line in file'. Пожалуйста, следуйте комментариям. –

+0

Моя ошибка, спасибо за отзыв! –

2

Использование буферизованного чтения из файла (Python 3):

buffer_size = 2**12 
delimiter = ',' 

with open(filename, 'r') as f: 
    # remember the characters after the last delimiter in the previously processed chunk 
    remaining = "" 

    while True: 
     # read the next chunk of characters from the file 
     chunk = f.read(buffer_size) 

     # end the loop if the end of the file has been reached 
     if not chunk: 
      break 

     # add the remaining characters from the previous chunk, 
     # split according to the delimiter, and keep the remaining 
     # characters after the last delimiter separately 
     *lines, remaining = (remaining + chunk).split(delimiter) 

     # print the parts up to each delimiter one by one 
     for line in lines: 
      print(line, end=delimiter) 

    # print the characters after the last delimiter in the file 
    if remaining: 
     print(remaining, end='') 

Обратите внимание, что путь этот в настоящее время написано, он будет просто распечатать содержимое исходного файла точно так, как они были. Это легко изменить, например, путем изменения параметра end=delimiter, переданного в функцию print() в цикле.

+0

'f.read()' буферизуется в любом случае, если вы не отключите его, так что не нужно делать это снова. – dhke

+0

@dhke Чтение символа с использованием 'f.read (1)' будет ужасно медленным из-за накладных вызовов функции Python, поэтому вы обязательно должны читать более крупные буферы за раз. Это также уменьшит количество раз, когда вам нужно вызвать 'str.split()'. –

+0

@dhke 'text = f.read()' будет читать содержимое всего файла в памяти, и так будет 'f.read.split (',')'. Буферизация, о которой вы упоминаете, находится на более низком уровне; код, использующий 'f.read()', должен быть написан тщательно, чтобы воспользоваться этим, и неясно, как это сделать, чтобы достичь того, что было задано в вопросе. – taleinat

0

Он дает каждому символу из файла сразу, что означает, что перегрузка памяти отсутствует.

def lazy_read(): 
    try: 
     with open('eggs.txt', 'rb') as file: 
      item = file.read(1) 
      while item: 
       if ',' == item: 
        raise StopIteration 
       yield item 
       item = file.read(1) 
    except StopIteration: 
     pass 

print ''.join(lazy_read()) 
+0

Что такое 'exit()'? Почему вы перебираете «линию», если в любом случае это только один символ? Кроме того, ваш отступ сломан. –