How to delete a specific line in a file?

545,400

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 of f.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.

Share:
545,400

Related videos on Youtube

SourD
Author by

SourD

Updated on January 02, 2021

Comments

  • SourD
    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
      Kevin about 8 years
      Try 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 simple for syntax.
  • John Machin
    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
    Ooker almost 10 years
    why do we have to open and close it twice?
  • Devin
    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
    Ooker almost 10 years
    Why does Python not allow us to do this in one line?
  • Waddas
    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
    Ooker almost 10 years
    I 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
    Easyrider over 9 years
    This 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
    shrishinde over 8 years
    Instead 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
    Steinar Lima over 8 years
    @Waddas Why not just move the cursor? This seems unnecessary complicated to me.
  • Steinar Lima
    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
    Steinar Lima over 8 years
    This 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
    Max over 7 years
    You 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
    Stephen Rauch over 7 years
    When giving an answer it is preferable to give some explanation as to WHY your answer is the one.
  • 7yl4r
    7yl4r over 6 years
    os.replace (new in python v 3.3) is more cross-platform than a system call to mv.
  • user1767754
    user1767754 over 6 years
    It would be nice to see some side effects of this solution.
  • yifan
    yifan over 5 years
    If f.seek(0) required?
  • Jamie Lindsey
    Jamie Lindsey over 5 years
    Anyone who suggests using subprocess for anything that can be done with just python gets a downvote! And +1 to @SteinarLima... I agree
  • Joshua Clayton
    Joshua Clayton over 5 years
    This 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
    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
    Boris Verkhovskiy about 5 years
    I 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 to f.truncate() right after f.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 use os.replace() or pathlib.Path(temp_filename).replace(original_filename) to swap it with the original after everything has succeeded.
  • Boris Verkhovskiy
    Boris Verkhovskiy about 5 years
    If 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
    Mangohero1 about 4 years
    Might you add i.strip('\n') != "line you want to remove..." as mentioned in the accepted answer, that would perfectly solve my problem. Because just i didn't do anything for me
  • Dionys
    Dionys almost 4 years
    there is no need for building a dict, just use for nb, line in enumerate(f.readlines())
  • tripleee
    tripleee about 3 years
    The only unique feature relative to existing older answers seems to be the indentation error.
  • tripleee
    tripleee about 3 years
    The -i option is nonstandard, and works differently on *BSD platforms (including macOS) than on Linux. Python's fileinput module does the same thing transparently, portably, and natively.