views:

195

answers:

5

What is the best way to undo the writing to a file? If I'm going through a loop and writing one line at a time, and I want to undo the previous write and replace it with something else, how do I go about doing that? Any ideas?

Thanks in advance!

+4  A: 

Try to write to your files lazily: Don't write until you are finally certain you need to do it.

Fragsworth
Yeah, that was one option but I'm processing a large amount of data and I'd rather keep a small subset of it in memory until it's flushed.
aspade
In this case, the small subset is *one* line that you are waiting to write.
S.Lott
A: 

If you keep track of the line numbers you can use something like this:

from itertools import islice 
def seek_to_line(f, n): 
    for ignored_line in islice(f, n - 1): 
        pass   # skip n-1 lines 


f = open('foo') 
seek_to_line(f, 9000)    # seek to line 9000 


# print lines 9000 and later 
for line in f: 
    print line
ennuikiller
@ennuikiller: I was thinking the same, but I wasn't quite sure if that was the best way to go about it. I guess sometimes you gotta do what works and not worry about what's fancy or not.
aspade
A: 

Perhaps a better thing to do would be to modify your program so that it will only write a line if you are sure that you want to write it. To do that your code would look something like:

to_write = ""
for item in alist:
  #Check to make sure that I want to write
  f.write(to_write)
  to_write = ""
  #Compute what you want to write.
  to_write = something

#We're finished looping so write the last part out
f.write(to_write)
David Locke
+4  A: 

as others have noted, this doesn't make much sense, it's far better not to write until you have to. in your case, you can keep the 'writing pointer' one line behind your processing.

pseudocode:

previousItem = INVALID
for each item I:
  is I same as previousItem?
    then update previousItem with I
    else
      write previousItem to file
      previousItem = I
write previousItem to file

as you can see, previousItem is the only item kept in memory, and it's updated to 'accumulate' as needed. it's only written to file when the next one isn't "the same as" that one.

of course, you could really rollback the file cursor, just keep track of the byte offset where the last line started and then do an fseek() to there before rewriting. at first it would seem simpler to code, but it's a total nightmare to debug.

Javier
+2  A: 

As mentioned, you're best off not trying to undo writes. If you really want to do it, though, it's easy enough:

import os
f = open("test.txt", "w+")
f.write("testing 1\n")
f.write("testing 2\n")
pos = f.tell()
f.write("testing 3\n")

f.seek(pos, os.SEEK_SET)
f.truncate(pos)
f.write("foo\n")

Just record the file position to rewind to, seek back to it, and truncate the file to that position.

The major problem with doing this is that it doesn't work on streams. You can't do this to stdout, or to a pipe or TCP stream; only to a real file.

Glenn Maynard