errorhandler
errorhandler

Reputation: 1767

Better way to remove a line in a file with python?

I want to remove a line in a file; currently I'm creating a new file, copying every line except the one I want to remove, deleting the old file and renaming the new one as the same filename as the old one. Is there a better way to remove a line?

f = open('./todo.txt', 'r')
newF = open('./todo-run.txt', 'a')
lines = f.readlines()
cLine = lines[int(index) - 1]

for line in lines:
  if line != cLine:
    newF.write(line)
f.close()
newF.close()
os.remove('./todo.txt')
shutil.move('./todo-run.txt', './todo.txt')

Upvotes: 0

Views: 289

Answers (4)

Kyle
Kyle

Reputation: 887

You could move the lines after the unwanted line up by overwriting one at a time. Not much better than what you're currently doing though. This code acts a little funny if the file doesn't end with a newline. I tested it on Win7 64-bit, Python 2.7.

move_lines.py:

f = open('todo.txt', 'r+')
line_index = 0
prev_line_head = 0
remove_line_index = 3
move_lines = False
while True:
  line_head = f.tell()
  line = f.readline()

  if line == '': #EOF
    f.seek(prev_line_head)
    f.truncate()
    break

  if move_lines:
    f.seek(prev_line_head)
    f.write(line)
    f.flush()
    line_head = f.tell()
    line = f.readline() # read past the line we already read to start this iteration
  elif line_index == remove_line_index:
    move_lines = True
  prev_line_head = line_head
  line_index += 1
f.close()

Upvotes: 0

Yann Vernier
Yann Vernier

Reputation: 15887

Better in what way? You could, for instance, shuffle the data within the file then truncate it, using less memory but more seeking (particularly if you adapt it to not read the latter part in one chunk):

def cutfile(file, startcut, endcut):
  file.seek(endcut)
  dataafter=file.read()
  file.seek(startcut)
  file.write(dataafter)
  file.truncate()

Or you could not remove the old file before renaming, to get atomic updates. It really depends on your goals.

Upvotes: 1

inspectorG4dget
inspectorG4dget

Reputation: 113975

It's not much better than yours, but (since your file seems to fit in main memory) you might try this:

f = open(filepath, 'r')
lines = [line.rstrip('\n') for line in f if not <CONDITION>]
f.close()
f.open('filepath, 'w')
f.write('\n'.join(lines))
f.close()

Upvotes: 0

Fredrik Pihl
Fredrik Pihl

Reputation: 45662

A solution in sed, which you might call using "subprocess". Ex, to delete line 18 do:

sed -i '18 d' filename

Upvotes: 2

Related Questions