LambdaLabTM
Computer Science · Class 12 · Text Files
Text filesThe pointer⏱️ 13 min read

seek() and tell()

Every open file has a marker in it, showing where the next read or write will happen. You have been moving it all chapter without seeing it. These two methods make it visible — and let you put it back.

1The file pointer

The file pointer (also called the file object's position) is a number: how far into the file you are, counted from the beginning. Opening a file in 'r', 'w' or 'r+' puts it at 0. Every read moves it forward by whatever was read.

f.tell()

Asks where the pointer is. Gives back a number and moves nothing.

f.seek(n)

Moves the pointer to position n, and gives back where it landed.

2tell() — watching it move

telling.py
f = open('notes.txt', 'r')

print(f.tell())
print(f.read(6))
print(f.tell())
print(f.readline())
print(f.tell())

f.close()
Output
0
Python
6
 is easy to learn.

25
f.tell() -> 0

A file opened for reading starts at the beginning. Nothing has been read yet.

f.read(6) -> 'Python'

Six characters, so the pointer is now 6. It sits just after the n, on the space.

f.readline() -> ' is easy to learn.\n'

The REST of that line, because reading always starts at the pointer, not at the start of the line.

f.tell() -> 25

The first line is 24 characters plus its newline, so 25 is the start of line two.

tell() counts bytes
For ordinary English text one character is one byte, so the number is also a count of characters. A file with accented letters or Hindi text stores some characters in two or three bytes, and then tell() jumps by more than one per character. Nothing in the syllabus depends on that — but it is why the value is a “position in bytes”, not “the letter number”.

3seek() — putting it back

This is the problem seek() solves. A file can only be read forwards, so once you have read to the end there is nothing left:

read_twice.py
f = open('notes.txt', 'r')

print(len(f.read()))
print(repr(f.read()))

f.seek(0)
print(len(f.read()))

f.close()
Output
74
''
74
seek(0) rewinds the file
The second read() gave '' because the pointer was at the end and there was nothing in front of it. seek(0) put it back at the beginning, and the same file read again perfectly. Any program that goes through a file twice needs this line in the middle.

seek() can move the pointer anywhere, not only to zero — and it hands back the position it moved to:

seeking.py
f = open('notes.txt', 'r')

print(f.seek(10))
print(f.read(5))
print(f.tell())

print(f.seek(0))
print(f.readline())

f.close()
Output
10
easy 
15
0
Python is easy to learn.

4seek() has a second argument

The full form is f.seek(offset, whence), where whence says what the offset is counted from:

Let's Recap!
whenceCounted fromWritten as
0the beginning of the file (the default)f.seek(10) or f.seek(10, 0)
1the current positionf.seek(0, 1)
2the end of the filef.seek(0, 2)

In text mode — which is all of this chapter — Python only allows the useful cases: seek(n) from the start, and seek(0, 1) or seek(0, 2) with an offset of exactly zero. That last one is a handy way to find how big a file is:

file_size.py
f = open('notes.txt', 'r')

f.seek(0, 2)
print('size in bytes:', f.tell())

f.close()
Output
size in bytes: 74
not_allowed.py
f = open('notes.txt', 'r')
f.seek(-5, 2)
Output
Traceback (most recent call last):
  File "not_allowed.py", line 2, in <module>
    f.seek(-5, 2)
io.UnsupportedOperation: can't do nonzero end-relative seeks
Why text mode is fussy about this
In text mode Python has to translate bytes into characters, and it cannot know where a character starts if you drop it five bytes before the end. Open the file in binary mode ('rb') and seek(-5, 2) works — which is why the binary-file chapter uses those forms freely and this one does not.

5What programs actually use it for

Reading a file twice
f.seek(0)

Count the lines, then go back and print the long ones. Without the rewind, the second pass reads nothing.

Reading a file you opened in 'a+'
f.seek(0)

Append modes open at the end, so read() gives '' until you send the pointer home.

Finding the size of a file
f.seek(0, 2); f.tell()

Jump to the end and ask where you are. That number is the file's size in bytes.

Overwriting from a known position
f.seek(0); f.write('JAVA')

With 'r+', writing lands on top of what is there, starting at the pointer.

6Try it

Comment out the seek(0) and run it again — the second count comes back 0:

rewind.py
📄 notes.txt

7Recap

The pointer is a position

How many bytes from the start of the file. Reading and writing both happen there.

f.tell()

Gives the position. It moves nothing.

f.seek(n)

Moves the pointer to n, counted from the start, and gives back the new position.

seek(0) is a rewind

The line that lets a program read the same file a second time.

seek(offset, whence)

whence is 0 from the start (default), 1 from here, 2 from the end. Text mode allows only offset 0 for the last two.

seek(0, 2) then tell()

The size of the file in bytes, without reading any of it.

✍️ Now write these yourself
  1. 1

    Print f.tell() after every call in a program that reads a file line by line.

    Hint · The numbers are the lengths of the lines, added up.

  2. 2

    Count the lines in a file, then print them — in one open().

    Hint · seek(0) between the two loops, or the second one sees nothing.

  3. 3

    Print the size of a file without reading it.

    Hint · seek(0, 2), then tell().

  4. 4

    Open a file in 'a+', print f.tell(), then read it.

    Hint · The pointer starts at the end, so seek(0) comes first.

Quick Check

What does f.tell() do?

Quick Check

A program calls f.read(), then f.read() again. Why is the second one empty?

Quick Check

What does f.seek(0, 2) do?

Quick Check

notes.txt starts with 'Python is easy to learn.' What is f.tell() after f.read(6)?