file.tell() after a write is not correct in append mode?

44 Views Asked by At

The method tell() returns a lower value than expected. It does not point to the position of the last written byte.

Consider this example:

# appender.py
import sys

file = open(sys.argv[1], 'a+b')
file.seek(0)
file.write(b'56789')
print('offset: ', file.tell())
$ printf "01234" > myfile
$ python appender.py myfile
offset:  5

The value should be 10 instead of 5.

This is an equivalence in C:

/* appender.c */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv){
  if (argc!=2){
    puts("usage ./test file");
    return 1;
  }
  int fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
  lseek(fd, 0, SEEK_SET);
  write(fd, "01234", 5);
  printf("offset: %ld\n", lseek(fd, 0, SEEK_CUR));
  return 0;
}

which returns the expected value:

$ printf "01234" > myfile
$ ./appender
offset: 10
1

There are 1 best solutions below

1
joanis On

From my experimentation, file.write() appends at the end of the file regardless of the seek position of the file.

If I augment your example like this:

# appender.py
import sys

file = open(sys.argv[1], 'a+b')
file.seek(0)
file.write(b'56789')
file.seek(0)
file.write(b'98765')
print('offset: ', file.tell())

and run your test:

$ printf "01234" > myfile
$ python appender.py myfile
offset:  5
$ cat myfile
012345678998765

Notice how both calls to file.seek(0) were effectively ignored.

Looking at the manual for open, it says this about mode:

and 'a' for appending (which on some Unix systems, means that all writes append to the end of the file regardless of the current seek position)

This appear to apply not just to Unix systems, but some others as well. I tested this with Python 3.11 on Windows in both cmd and Git Bash and got the same behaviour.