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
f = open('notes.txt', 'r')
print(f.tell())
print(f.read(6))
print(f.tell())
print(f.readline())
print(f.tell())
f.close()0 Python 6 is easy to learn. 25
f.tell() -> 0A 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() -> 25The first line is 24 characters plus its newline, so 25 is the start of line two.
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:
f = open('notes.txt', 'r')
print(len(f.read()))
print(repr(f.read()))
f.seek(0)
print(len(f.read()))
f.close()74 '' 74
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:
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()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:
| whence | Counted from | Written as |
|---|---|---|
| 0 | the beginning of the file (the default) | f.seek(10) or f.seek(10, 0) |
| 1 | the current position | f.seek(0, 1) |
| 2 | the end of the file | f.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:
f = open('notes.txt', 'r')
f.seek(0, 2)
print('size in bytes:', f.tell())
f.close()size in bytes: 74
f = open('notes.txt', 'r')
f.seek(-5, 2)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'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
f.seek(0)Count the lines, then go back and print the long ones. Without the rewind, the second pass reads nothing.
f.seek(0)Append modes open at the end, so read() gives '' until you send the pointer home.
f.seek(0, 2); f.tell()Jump to the end and ask where you are. That number is the file's size in bytes.
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:
7Recap
How many bytes from the start of the file. Reading and writing both happen there.
Gives the position. It moves nothing.
Moves the pointer to n, counted from the start, and gives back the new position.
The line that lets a program read the same file a second time.
whence is 0 from the start (default), 1 from here, 2 from the end. Text mode allows only offset 0 for the last two.
The size of the file in bytes, without reading any of it.
- 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
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
Print the size of a file without reading it.
Hint · seek(0, 2), then tell().
- 4
Open a file in
'a+', printf.tell(), then read it.Hint · The pointer starts at the end, so seek(0) comes first.
What does f.tell() do?
A program calls f.read(), then f.read() again. Why is the second one empty?
What does f.seek(0, 2) do?
notes.txt starts with 'Python is easy to learn.' What is f.tell() after f.read(6)?