with open('test.txt', 'w+') as f:
f.write('foo')
f.seek(0)
f.read(1)
print f.tell() # 1
f.write('bar')
I want the result to be fbar
but it returns foobar
. Obviously, file does not write at the current file position.
with open('test.txt', 'w+') as f:
f.write('foo')
f.seek(0)
f.read(1)
m = f.tell() # 1
f.seek(m)
f.write('bar')
It works as I expect.
why do I need seek
again while the current file position is already in 1
?
this is caused by the fact that open
returns a buffered file object.
When you're reading, it reads all the file behind the scenes because of buffering (because reading char by char from disk is inefficient).
f.tell()
is coherent with what you've read, but internally when you write, the file pointer is somewhere else, that's why you have to workaround it by forcing the seek
.
That's only the "why?", but IMHO it's a bug (or a limitation), as write
should/could use user-known position not internal system position of the underlying unbuffered file.
That's not a problem on read-only or write-only streams, but that's a problem in that interesting case.
So now you know: to read
after a write
or write
after a read
, always use seek
even if you think that the position of the file is correct.
As an alternative, you could use os.open
to make sure buffering isn't involved (with some adaptations for the system calls as ftell
doesn't exist, you have to seek 0 from current to get current pos):
import os
f = os.open('test.txt',os.O_RDWR|os.O_TRUNC)
os.write(f,b'foo') # b prefix needed, stream is binary
os.lseek(f, 0, os.SEEK_SET)
os.read(f,1)
# print(os.lseek(f, 0, os.SEEK_CUR)) # to seek/get current
os.write(f,b'bar')
os.close(f)
you get fbar
all right in that case (even when disabling the lseek
statement)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.