13

I've been trying to read a file and then overwrite it with some updated data. I've tried doing it like this:

#Created filename.txt with some data
with open('filename.txt', 'r+') as f:
    data = f.read()
    new_data = process(data)  # data is being changed
    f.seek(0)
    f.write(new_data)

For some reason, it doesn't overwrite the file and the content of it stays the same.

pystudent
  • 531
  • 1
  • 5
  • 19
  • 1
    Could you elaborate on what's not working? – Loïc Faure-Lacroix Feb 28 '16 at 06:11
  • Does it read the file but not write it, or nothing at all? – Menasheh Feb 28 '16 at 06:12
  • `w+` truncates a file, so this will always be empty on the `f.read()`. `a+` also creates the file but you will need to seek to the beginning before reading. – AChampion Feb 28 '16 at 06:15
  • @AChampion you're right, I've changed my question a bit. – pystudent Feb 28 '16 at 06:19
  • What's not working this will over-write the data - but will leave data behind if the update is smaller than the original. Just split the call over 2 `with` statements one `with open(..., 'r')` and one `with open(..., 'w')` - truncates. – AChampion Feb 28 '16 at 06:23
  • @AChampion I've tried using this, but it still doesn't overwrites the data. does the second "with open(...)" have to be not inside the first one? – pystudent Feb 28 '16 at 06:29
  • The code you show will overwrite the beginning of the file but if the old file was bigger than the new data, the end of the old file will remain. Use f.truncate() to erase. – tdelaney Feb 28 '16 at 06:30
  • @tdelaney I've tried adding this above f.write(...) and it still doesn't overwrite anything... – pystudent Feb 28 '16 at 06:34
  • I added an answer demonstrating... does that work? – tdelaney Feb 28 '16 at 06:36
  • @pystudent did you actually checked that `new_data` contains modified data? – Samuel Feb 28 '16 at 06:57

2 Answers2

11

Truncate the file after seeking to the front. That will remove all of the existing data.

>>> open('deleteme', 'w').write('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
>>> f = open('deleteme', 'r+')
>>> f.read()
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> f.seek(0)
>>> f.truncate()
>>> f.write('bbb')
>>> f.close()
>>> open('deleteme').read()
'bbb'
>>> 
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • It still doesn't work. I'm using the code in a loop and each time the data read from the file is the original data I gave it before the loop started - it doesn't overwrite the file... – pystudent Feb 28 '16 at 06:40
  • Then we may have to blame your other code. For instance, does `process` just return the same data? (you could add `assert data != new_data` to debug. Maybe you are writing a different file than you think. Use `os.path.abspath` to print the file you actually use. – tdelaney Feb 28 '16 at 06:46
  • Thank you for your answer, I've found the problem in another place in my code, just as you suggested. – pystudent Feb 28 '16 at 07:08
  • For some reason this is the only answer I found that put `.truncate()` in the right place. Yay – Chaim Eliyah May 28 '21 at 02:35
2

You should add a call to truncate after seek as tdelaney suggested.

Try reading and writing in different scopes, the code is more clear that way and the data processing is not done when the file handlers are open.

data = ''
with open('filename.txt', 'r') as f:
    data = f.read()

new_data = process(data)  
with open('filename.txt', 'w+') as f:
    f.write(new_data)
Community
  • 1
  • 1
Forge
  • 6,538
  • 6
  • 44
  • 64