Python обрезает строки по мере их чтения.
У меня есть приложение, которое считывает строки из файла и запускает его магию на каждой строке по мере ее чтения. Как только строка будет прочитана и обработана правильно, я хотел бы удалить строку из файла. Резервная копия удаленной строки уже сохраняется. Я хотел бы сделать что-то вроде
file = open('myfile.txt', 'rw+')
for line in file:
processLine(line)
file.truncate(line)
Это кажется простой проблемой, но я хотел бы сделать это правильно, а не много сложных вызовов seek() и tell().
Возможно, все, что я действительно хочу сделать, это удалить определенную строку из файла.
Проведя много времени на эту проблему, я решил, что все, вероятно, правы, и это просто не очень хороший способ сделать что-то. Это просто казалось таким изящным решением. То, что я искал, было чем-то вроде FIFO, который просто дал бы мне поп-строки из файла.
Ответы
Ответ 1
Удалите все строки после того, как вы покончили с ними:
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'
В общем, как уже говорили другие люди, плохо то, что вы пытаетесь сделать.
Ответ 2
Вы не можете. Это просто невозможно с реализацией реальных текстовых файлов в текущих файловых системах.
Текстовые файлы являются последовательными, поскольку строки в текстовом файле могут иметь любую длину.
Удаление определенной строки означает переписывание всего файла с этой точки.
Предположим, что у вас есть файл со следующими тремя строками:
'line1\nline2reallybig\nline3\nlast line'
Чтобы удалить вторую строку, вам нужно будет перемещать позиции третьего и четвертого строк на диске. Единственный способ - сохранить третью и четвертую строки где-нибудь, усечь файл на второй строке и переписать недостающие строки.
Если вы знаете размер каждой строки текстового файла, вы можете обрезать файл в любой позиции с помощью .truncate(line_size * line_number)
, но даже тогда вам придется переписать все после строки.
Ответ 3
Вам лучше хранить индекс в файле, чтобы вы могли начать с того, где вы остановились последним, не уничтожая часть файла. Что-то вроде этого будет работать:
try :
for index, line in enumerate(file) :
processLine(line)
except :
# Failed, start from this line number next time.
print(index)
raise
Ответ 4
Усечение файла по мере чтения кажется немного экстремальным. Что делать, если ваш script имеет ошибку, которая не вызывает ошибку? В этом случае вам нужно перезапустить в начале файла.
Как насчет того, чтобы ваш script распечатывал номер строки, в котором он ломался, и чтобы он брал номер строки в качестве параметра, чтобы вы могли указать, с какой строки начать обработку?
Ответ 5
Прежде всего, вызов операции truncate
, вероятно, не лучший выбор. Если я правильно понял проблему, вы хотите удалить все до текущей позиции в файле. (Я бы ожидал, что truncate
вырезает все из текущей позиции до конца файла. Вот как работает стандартный метод Python truncate
, по крайней мере, если я правильно разобрался.)
Во-вторых, я не уверен, что было бы разумно изменить файл при повторении с использованием цикла for
. Не лучше ли было бы сохранить количество обработанных строк и удалить их после завершения основного цикла, исключения или нет? Итератор файлов поддерживает фильтрацию на месте, что означает, что после этого должно быть довольно просто удалить обработанные строки.
P.S. Я не знаю Питона, возьмите это с солью.
Ответ 6
У связанного сообщения есть то, что кажется хорошей стратегией для этого, см.
Как запустить первый процесс из списка процессов, хранящихся в файле, и сразу удалить первую строку, как если бы файл был в очереди, и я назвал "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. Пробовал это на маке, и он сделал трюк.
Ответ 7
Это то, что я использую для файловых очередей. Он возвращает первую строку и переписывает файл с остальными. Когда это будет сделано, он вернет 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