Глава 15 · Python и файлы

Курсор файла: tell() и seek()

У открытого файла есть текущая позиция — она двигается вперёд, но сама назад не возвращается.

Курсор файла

У открытого файла есть текущая позиция чтения/записи — курсор. Он двигается вперёд по мере чтения или записи:

kursor.py
with open("alfavit.txt", "w", encoding="utf-8") as f:
    f.write("ABCDE")

with open("alfavit.txt", "r", encoding="utf-8") as f:
    print(f.read(2))   # AB — курсор передвинулся на 2
    print(f.read(2))   # CD — курсор передвинулся ещё на 2
    print(f.read())    # E  — до конца файла
    print(repr(f.read()))   # '' — курсор уже в конце
0
1
2
3
4
5
A
B
C
D
E
прочитаноосталось
Курсор перед первым read(2): позиция 0.
0
1
2
3
4
5
A
B
C
D
E
прочитаноосталось
После read(2): курсор на позиции 2, прочитано «AB».
0
1
2
3
4
5
A
B
C
D
E
прочитаноосталось
После второго read(2): курсор на позиции 4, прочитано «ABCD».
0
1
2
3
4
5
A
B
C
D
E
прочитаноосталось
После read(): курсор в конце файла (EOF), позиция 5.
Debug Lab 3: Курсор уже в конце файла
posle_eof.py
with open("alfavit.txt", "r", encoding="utf-8") as f:
    print(f.read())
    print(f.read())   # ожидаем увидеть то же самое ещё раз?
ABCDE
(пустая строка)
Что видно на экране

Второй f.read() вернул пустую строку, а не «ABCDE» снова. Курсор не возвращается в начало сам — после первого read() он остался в конце файла (EOF), и там больше нечего читать.

Исправленный код
vozvrat_v_nachalo.py
with open("alfavit.txt", "r", encoding="utf-8") as f:
    print(f.read())
    f.seek(0)          # вручную возвращаем курсор в начало
    print(f.read())    # теперь снова ABCDE

tell() и seek()

tell_seek.py
with open("alfavit.txt", "r", encoding="utf-8") as f:
    f.read(2)
    print(f.tell())   # 2 — текущая позиция курсора
    f.seek(0)         # вернуться в начало
    print(f.read())   # ABCDE — читаем заново
seek() в текстовом режиме — не «номер символа»
Для простых примеров с ASCII-текстом смещение, которое возвращает tell(), интуитивно совпадает с числом прочитанных символов. Но в общем случае для текста в UTF-8 это неверно: один символ (особенно кириллица или эмодзи) может занимать несколько байт (раздел 15.16), и произвольные смещения не соответствуют напрямую индексам символов. Для произвольных байтовых смещений понятнее и безопаснее работать в бинарном режиме (раздел 15.17). Безопасное использование seek() в текстовом режиме — seek(0), чтобы начать чтение сначала.
Практика: курсор файла, tell() и seek()
Интерактивный ноутбук прямо в браузере — Python 3.14 через Pyodide, без установки
Открыть практику →