3

These are the contents of the contacts.txt file:

foo 69

bar 70

baz 71

I want to delete "foo 69" and this is what I did:

with open('contacts.txt','a+') as f:
    for line in f:
        with open('contacts.txt','a+') as f:
            if "foo" in line:
                line.replace("foo", "")

It did not do anything.

Community
  • 1
  • 1
  • delete the whole line or just foo? – depperm Jan 12 '17 at 13:52
  • 2
    `line` is a string, calling `line.replace("foo", "")` returns `""` however doesn't actually affect the string as the function does not happen in place. Even if it did, it does not write it back to the file. – Nick is tired Jan 12 '17 at 13:52
  • @hiroprotagonist okay I stored it in a variable and wrote to the file. Now the result is the same text file but with a " 69" at the end. – calm like a bomb Jan 12 '17 at 13:55
  • Nor you are writing the modified content back no you are opening files correctly(why open twice ?). First try opening the file in read mode and read all the contents. Now use replace statement ```content.replace("content_to_replace"," ")``` and then write this content back to file. – Gurupad Mamadapur Jan 12 '17 at 13:55
  • @calmlikeabomb `content.replace("foo 69"," ")` , use `69` also to replace. – Gurupad Mamadapur Jan 12 '17 at 13:56
  • @GurupadMamadapur I tried 'r', tried to write into it but nothing happens. this is what i did: – calm like a bomb Jan 12 '17 at 14:00
  • `gone = line.replace("foo 69", "")` `f.write(gone)` – calm like a bomb Jan 12 '17 at 14:00
  • @NickA okay, stored it in a variable and wrote to the file. Nothing happens – calm like a bomb Jan 12 '17 at 14:01
  • open file for reading and read everything into memory and close file, next change text, next open file for writing and write everthing in file and close file. It is correct method to remove text and doesn't get empty place in file. – furas Jan 12 '17 at 14:03
  • @calmlikeabomb check my answer, on what I meant. I'll edit it soon to point out mistakes with your approach. – Gurupad Mamadapur Jan 12 '17 at 14:09

2 Answers2

1

I'm not sure exactly what you want the output to be like (e.g. if you want lines above bar 70 to be removed as well) but this code will literally just remove foo 69 from the file. It only needs to open a reference to the file once:

with open('contacts.txt', 'r+') as f:
    content = f.read()
    new_content = content.replace('foo 69', '')
    f.seek(0)
    f.write(new_content)
    f.truncate()

In the snippets below, I'm using . in place of newlines for formatting purposes.

contacts.txt before:

foo 69
.
bar 70
.
baz 71

contacts.txt after:

.
.
bar 70
.
baz 71
Tagc
  • 8,736
  • 7
  • 61
  • 114
  • Never knew about the truncate and seek, I'm a beginner (gee, do I seem like one?). That's new information to me, thank you for sharing that! Will definitely help me in the future. Your code makes a lot of sense. – calm like a bomb Jan 12 '17 at 15:17
1

The correct way is to first the read the content completely, make your modifications and then write back to the file.

This approach is clean and readable too.

#first read everything
with open('file_name','r') as f:
        content =  f.read()

#now perform modifications
content = content.replace('foo 69','')

#now write back to the file
with open('file_name','w') as f:
        f.write(content)

Now, I've commented some of the problems you had in your code:

with open('file_name','a+') as f:
    for line in f:#here you are iterating through the content of the file
        # at each iteration line will equal foo 69, then bar 70 and then bar 71...

        # Now, there is no reason to open the file here again, I guess you opened
        # it to write again, but your mode is set to `a` which will append contents
        # not overwrite them
        with open('contacts.txt','a+') as f:
            if "foo" in line:
                line.replace("foo", "") #here the modified content is lost
                # because you're not storing them anywhere

Edit - As mentioned in the comments, if your file is quite large and you do not want to read all the contents.

Then the best way to do this is to read the content line by line and write contents to another file excluding the line you want to delete.

to_replace = 'foo 69\n' #note \n is neccessary here
with open('input.txt','r') as input_file:
    with open('ouput.txt','w') as output:
        for line in input_file:
            if line!=to_replace:
                output.write(line)


#Now, let's say you want to delete all the contents of the input_file
#just open it in write mode and close without doing anything
input_file = open('input_file.txt','w')
input_file.close()

# If you want to delete the entire input_file and rename output_file to
# original file_name then you can do this in case of linux OS using subprocess
subprocess.call(['mv', 'output_file.txt', 'input_file.txt'])

This is very memory efficient because only a single line of content is in memory at any point of time. input_file is only a pointer to the file and the iteration - for line in input_file does not read the whole file and start iterating the content one by one.

Gurupad Mamadapur
  • 989
  • 1
  • 13
  • 24
  • 2
    What if the file is very large so you don't want to load all of it into memory but rather do the modifications on the fly? –  Jan 12 '17 at 14:17
  • @SembeiNorimaki Yes I agree on that note. Doing modifications on the fly is better. But, here it seemed like OP had a smaller file. Also, to do modifications on the fly is riskier and termed as a `hornets nests` here in this answer - http://stackoverflow.com/a/5453315/3225001 – Gurupad Mamadapur Jan 12 '17 at 14:18
  • @SembeiNorimaki I've included an approach for large files in the answer. Thanks for letting me know. – Gurupad Mamadapur Jan 12 '17 at 14:54
  • It worked! Thank you so much, I understood what you were saying now. But, you complained earlier about me opening the same file twice, and seems to me you did, too. May I ask, what purpose does reading serve if I can just write/append since I just want to edit: my intention was to .replace() after all, why read? – calm like a bomb Jan 12 '17 at 15:13
  • 1
    @GurupadMamadapur also, I saw the edit just now, I'm back from doing some things. I understand my careless mistake treating `.replace()` as an actual command instead of storing it in a variable, will never do that again. Again, thank you for the detailed and well explained answer! – calm like a bomb Jan 12 '17 at 15:22
  • @calmlikeabomb You're welcome. I didn't get why you were trying to open files twice with the same mode `a+`. If you had opened twice with different mode and different alias instead of `f` then it would have looked like you're trying to do something. – Gurupad Mamadapur Jan 12 '17 at 15:22
  • @GurupadMamadapur another question: when I tried this on my main code, I needed to print out the contents of the text file after removing "foo 69" (contents of text file are copied into a dictionary) but it says it cannot print since list index is out of range. I believe the problem is caused by the empty line in the text file left by removing the "foo 69". What do I do? – calm like a bomb Jan 12 '17 at 15:37
  • @calmlikeabomb Which approach did you use and how are you reading the contents of file again ? May be post this as a separate question. – Gurupad Mamadapur Jan 12 '17 at 15:57
  • @calmlikeabomb You were opening the file in a loop the second time. You should open both at the beginning and then iterate. –  Jan 12 '17 at 16:15