Reputation: 1767
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
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
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
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
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