Усеченные строки Python по мере их чтения - PullRequest
10 голосов
/ 08 февраля 2009

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

file = open('myfile.txt', 'rw+')
for line in file:
   processLine(line)
   file.truncate(line)

Это кажется простой проблемой, но я бы хотел сделать это правильно, а не множество сложных вызовов seek () и tell ().

Может быть, все, что я действительно хочу сделать, это удалить определенную строку из файла.

Потратив слишком много времени на эту проблему, я решил, что все, вероятно, правы, и это просто не хороший способ сделать что-то. Это просто казалось таким элегантным решением. То, что я искал, было чем-то похожим на FIFO, который позволял бы мне выводить строки из файла.

Ответы [ 7 ]

17 голосов
/ 08 февраля 2009

Удалить все строки после того, как с ними покончено:

with open('myfile.txt', 'rw+') as file:
    for line in file:
        processLine(line)
    file.truncate(0)

Удалить каждую строку независимо:

lines = open('myfile.txt').readlines()

for line in lines[::-1]: # process lines in reverse order
    processLine(line)
    del lines[-1]  # remove the [last] line

open('myfile.txt', 'w').writelines(lines)

Вы можете оставить только те строки, которые вызывают исключения:

import fileinput

for line in fileinput.input(['myfile.txt'], inplace=1):
    try: processLine(line)
    except Exception:
         sys.stdout.write(line) # it prints to 'myfile.txt'

В общем, как уже говорили другие люди, плохая идея, что вы пытаетесь сделать.

8 голосов
/ 08 февраля 2009

Вы не можете . Это просто невозможно с реальными реализациями текстовых файлов в текущих файловых системах.

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

Предположим, у вас есть файл со следующими 3 строками;

'line1\nline2reallybig\nline3\nlast line'

Чтобы удалить вторую строку, вам нужно переместить позиции третьей и четвертой строк на диске. Единственный способ - где-то сохранить третью и четвертую строки, обрезать файл во второй строке и переписать пропущенные строки.

Если вы знаете размер каждой строки в текстовом файле, вы можете обрезать файл в любой позиции, используя .truncate(line_size * line_number), но даже тогда вам придется переписывать все после строки.

6 голосов
/ 08 февраля 2009

Вам лучше хранить индекс в файле, чтобы вы могли начать с того места, где остановились в последний раз, не уничтожая часть файла. Примерно так будет работать:

try :
    for index, line in enumerate(file) :
        processLine(line)
except :
    # Failed, start from this line number next time.
    print(index)
    raise
4 голосов
/ 08 февраля 2009

Прежде всего, вызов операции truncate, вероятно, не лучший выбор. Если я правильно понимаю проблему, вы хотите удалить все до текущей позиции в файле. (Я ожидаю, что truncate обрежет все от текущей позиции до конца файла. Так работает стандартный метод Python truncate, по крайней мере, если я правильно гуглил.)

Во-вторых, я не уверен, что было бы разумно изменить файл при повторении в цикле for. Не лучше ли сохранить количество обработанных строк и удалить их после завершения основного цикла, исключение или нет? Файловый итератор поддерживает фильтрацию на месте , что означает, что после этого будет достаточно просто отбросить обработанные строки.

P.S. Я не знаю Python, возьми это с крошкой соли.

4 голосов
/ 08 февраля 2009

Усечение файла при чтении кажется немного экстремальным. Что если в вашем скрипте есть ошибка, которая не вызывает ошибку? В этом случае вы захотите перезапустить файл с начала.

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

2 голосов
/ 13 мая 2010

В соответствующем посте есть хорошая стратегия, см. Как запустить первый процесс из списка процессов, хранящихся в файле, и сразу же удалить первую строку, как если бы файл был очередью, а я назвал «pop»?

Я использовал его следующим образом:

  import os;

  tasklist_file = open(tasklist_filename, 'rw');  
  first_line = tasklist_file.readline();
  temp = os.system("sed -i -e '1d' " + tasklist_filename); # remove first line from task file;

Я не уверен, что это работает в Windows. Попробовал его на Mac, и он сделал свое дело.

1 голос
/ 16 марта 2017

Это то, что я использую для файловых очередей. Возвращает первую строку и переписывает файл с остальными. Когда это сделано, возвращается None:

def pop_a_text_line(filename):
    with open(filename,'r') as f:
        S = f.readlines()
    if len(S) > 0:
        pop = S[0]
        with open(filename,'w') as f:
            f.writelines(S[1:])
    else:
        pop = None
    return pop
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...