Re: Problem with f.seek(offset,whence)

"Martin A. Brown via Tutor" <[email protected]> Wed, 20 Aug 2025 17:37:48 -0700
Newsgroups gmane.comp.python.tutor
Message-ID <[email protected]>
Hello Heiko,

> surely it is an old question, but I did not find any answers.  
> 
> -- snip 
>  f = open('test.txt','w+')

Here, you are opening the file, but not in binary mode.  If you take 
a look at what the file object is, you will see:

  <_io.TextIOWrapper name='test.txt' mode='w+' encoding='UTF-8'>

So, Python is doing some work for you, reading bytes from the 
underlying file, using the encoding to turn them into strings.

>  f.write('0123456789')
> 10

This works just fine. Because it's ASCII, one byte = one character, 
but the TextIOWrapper doesn't know that your whole file contains 
only ASCII.

>  f.seek(2)
> 2
>  f.seek(2,1)

Imagine if byte 2 in the file is not the first in a multibyte 
encoding of a character. What should the TextIoWrapper do now?

> -- snap 
> results in the error message
>      io.UnsupportedOperation: can't do nonzero cur-relative seeks

>
> I do not know, what the problem is.  If you can place the cursor 
> with f.seek(2) at an absolute position, it must be possible, to 
> change its position relative (whence = 1) to 2+2 = 4.
> 
> f.seek(0,2) functions (end of file), but not f.seek(-1,2) (same error).  

I can make `f.seek(8, 0)` complain, by seeking to the second byte of a
multibyte UTF-8 character and trying to read:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb6 in position 0: invalid start byte

Essentially, the problem is mixing up bytes and characters. Fortunately,
there are tools to work around this (and probably third-party libraries
of which I'm unaware).

> 
> Do  you know, what's wrong?  The examples of the KI do not function as well.  

Consider opening the file in binary mode and operating on a bytestream.

Your application must convert anything you are writing into a bytes, and
convert anything reading into ...well strings or whatever your
application is storing.

Using binary mode behaves more like you expect, though now your program
needs to account for all encoding and decoding issues, as well.

  <_io.BufferedRandom name='test.txt'>

So, the following should print out bytes, 2, 5, and 7.

  f = open("test.txt", "wb+")
  f.write(b"0123456789")
  f.seek(2, 0)
  print(f.read(1))
  f.seek(2, 1)
  print(f.read(1))
  f.seek(-3, 2)
  print(f.read(1))

Output (on my system):

  b'2'
  b'5'
  b'7'

If the data you are handling fits comfortably in RAM, then you may find
the benefits of the TextIOWrapper handling encoding for you outweighs
the control offered for arbitrary `seek()` and `tell()`.

But, perhaps you need the low-level control -- and if you do, Python has
tools for you, as well.

-Martin

-- 
Martin A. Brown
http://linux-ip.net/
_______________________________________________
Tutor maillist  -  To unsubscribe send an email to [email protected]
To unsubscribe or change subscription options:
%(web_page_url)slistinfo/%(_internal_name)s