How to delete a specific line in a file?
Solution 1
First, open the file and get all your lines from the file. Then reopen the file in write mode and write your lines back, except for the line you want to delete:
with open("yourfile.txt", "r") as f:
lines = f.readlines()
with open("yourfile.txt", "w") as f:
for line in lines:
if line.strip("\n") != "nickname_to_delete":
f.write(line)
You need to strip("\n")
the newline character in the comparison because if your file doesn't end with a newline character the very last line
won't either.
Solution 2
Solution to this problem with only a single open:
with open("target.txt", "r+") as f:
d = f.readlines()
f.seek(0)
for i in d:
if i != "line you want to remove...":
f.write(i)
f.truncate()
This solution opens the file in r/w mode ("r+") and makes use of seek to reset the f-pointer then truncate to remove everything after the last write.
Solution 3
The best and fastest option, rather than storing everything in a list and re-opening the file to write it, is in my opinion to re-write the file elsewhere.
with open("yourfile.txt", "r") as file_input:
with open("newfile.txt", "w") as output:
for line in file_input:
if line.strip("\n") != "nickname_to_delete":
output.write(line)
That's it! In one loop and one only you can do the same thing. It will be much faster.
Solution 4
This is a "fork" from @Lother's answer (which I believe that should be considered the right answer).
For a file like this:
$ cat file.txt
1: october rust
2: november rain
3: december snow
This fork from Lother's solution works fine:
#!/usr/bin/python3.4
with open("file.txt","r+") as f:
new_f = f.readlines()
f.seek(0)
for line in new_f:
if "snow" not in line:
f.write(line)
f.truncate()
Improvements:
with open
, which discard the usage off.close()
- more clearer
if/else
for evaluating if string is not present in the current line
Solution 5
The issue with reading lines in first pass and making changes (deleting specific lines) in the second pass is that if you file sizes are huge, you will run out of RAM. Instead, a better approach is to read lines, one by one, and write them into a separate file, eliminating the ones you don't need. I have run this approach with files as big as 12-50 GB, and the RAM usage remains almost constant. Only CPU cycles show processing in progress.
Related videos on Youtube
SourD
Updated on January 02, 2021Comments
-
SourD over 3 years
Let's say I have a text file full of nicknames. How can I delete a specific nickname from this file, using Python?
-
Kevin about 8 yearsTry
fileinput
as described by @j-f-sebastian here. It seems to allow you to work line-by-line, via a temporary file, all with a simplefor
syntax.
-
-
John Machin over 13 years(1) do you mean
tuple(f.read().split('\n'))
?? (2) "access your tuple's line number" and "join your result tuple" sound rather mysterious; actual Python code might be more understandable. -
Ooker almost 10 yearswhy do we have to open and close it twice?
-
Devin almost 10 years@Ooker: You have to open the file twice (and close it in between) because in the first mode it is "read-only" because you are just reading in the current lines in the file. You then close it and re-open it in "write mode", where the file is writable and you replace the contents of the file sans the line you wanted to remove.
-
Ooker almost 10 yearsWhy does Python not allow us to do this in one line?
-
Waddas almost 10 years@Ooker, When you read a line, try to imagine a cursor moving along the line as it's read. Once that line has been read the cursor is now past it. When you try to write into the file you write where the cursor currently is. By re-opening the file you reset the cursor.
-
Ooker almost 10 yearsI didn't know that it is that complicate. Thank you. If we have a reset cursor function, does that mean we don't need to close and re-open it?
-
Easyrider over 9 yearsThis worked very well for me, as I had to use lockfile also (fcntl). I couldnt find any way to use fileinput together with fcntl.
-
shrishinde over 8 yearsInstead of using normal for loop we can make use of Generator Expression This way program will not load all the lines from file to memory which is not good idea in case of big files. It will only have single line in memory at a time. With generator expression for loop will look like,
(output.write(line) for line in input if line!="nickname_to_delete"+"\n")
-
Steinar Lima over 8 years@Waddas Why not just move the cursor? This seems unnecessary complicated to me.
-
Steinar Lima over 8 years@ShriShinde You're not reading the file into memory when looping over the file object either, so this solution works identical to your suggestion.
-
Steinar Lima over 8 yearsThis solution isn't OS agnostic, and since OP didn't specify a operation system, there's no reason to post a Linux specific answer imo.
-
Max over 7 yearsYou might want to delete the original file and rename the second file to the original file's name, which with Python on a Linux OS would look like this,
subprocess.call(['mv', 'newfile.txt', 'yourfile.txt'])
-
Stephen Rauch over 7 yearsWhen giving an answer it is preferable to give some explanation as to WHY your answer is the one.
-
7yl4r over 6 years
os.replace
(new in python v 3.3) is more cross-platform than a system call tomv
. -
user1767754 over 6 yearsIt would be nice to see some side effects of this solution.
-
yifan over 5 yearsIf f.seek(0) required?
-
Jamie Lindsey over 5 yearsAnyone who suggests using subprocess for anything that can be done with just python gets a downvote! And +1 to @SteinarLima... I agree
-
Joshua Clayton over 5 yearsThis task can be done opening the file only once... but it needs to be opened 'r+', AND , you'd need to call flie.seek(0) (to move the cursor to the beginning) and file.truncate() (to invalidate the existing contents), before proceeding to rewrite it out.
-
Boris Verkhovskiy about 5 years@yifan yes. Otherwise instead of overwriting the file you'll append the file to itself (without the lines you're excluding).
-
Boris Verkhovskiy about 5 yearsI wouldn't do this. If you get an error in the
for
loop, you'll end up with a partially overwritten file, with duplicate lines or a line half cut off. You might want tof.truncate()
right afterf.seek(0)
instead. That way if you get an error you'll just end up with an incomplete file. But the real solution (if you have the disk space) is to output to a temporary file and then useos.replace()
orpathlib.Path(temp_filename).replace(original_filename)
to swap it with the original after everything has succeeded. -
Boris Verkhovskiy about 5 yearsIf your file doesn't end with a newline, this code won't remove the last line even if it contains a word you want to remove.
-
Mangohero1 about 4 yearsMight you add
i.strip('\n') != "line you want to remove..."
as mentioned in the accepted answer, that would perfectly solve my problem. Because justi
didn't do anything for me -
Dionys almost 4 yearsthere is no need for building a dict, just use
for nb, line in enumerate(f.readlines())
-
tripleee about 3 yearsThe only unique feature relative to existing older answers seems to be the indentation error.
-
tripleee about 3 yearsThe
-i
option is nonstandard, and works differently on *BSD platforms (including macOS) than on Linux. Python'sfileinput
module does the same thing transparently, portably, and natively.