Справочник по Python · модуль 8 · исключения и файлы
Глава 8.8
Чтение:
read()
Метод возвращает содержимое файла одной строкой. Без аргумента — целиком, с числом — указанное количество символов. Ключ к пониманию всех методов чтения — позиция в файле: она сдвигается при каждом вызове и объясняет, почему повторный read() возвращает пустоту.
- Категория
- Файлы
- Уровень
- Базовый
- Связанные темы
- Строки, позиция в файле, память
- Зачем это знать
- Получать содержимое файла в переменную
§1read() без аргумента
Вызов без аргументов возвращает всё содержимое файла как одну строку.
with open("demo.txt", encoding="utf-8") as file: content = file.read() print(repr(content))
'первая строка\nвторая строка\nтретья строка\n'
Результат — обычная строка со всеми свойствами из модуля 5: к ней применимы срезы, split(), find() и остальные методы.
§2Позиция в файле
У открытого файла есть позиция — место, откуда пойдёт следующее чтение. Сразу после открытия она равна нулю, а любое чтение её сдвигает.
with open("demo.txt", encoding="utf-8") as file: print(file.tell()) file.read(5) print(file.tell())
0 10
Число 10 вместо ожидаемых 5 — не ошибка: tell() считает байты, а пять кириллических символов занимают в UTF-8 десять байт. Подробно об этом — глава 8.11.
§3Повторный вызов
Из механики позиции следует поведение, которое ставит в тупик каждого второго новичка.
with open("demo.txt", encoding="utf-8") as file: first = file.read() second = file.read() print(len(first)) print(repr(second))
42 ''
После первого read() позиция стоит в конце, и всё последующее чтение возвращает пустоту. Ошибки при этом нет — программа спокойно работает с пустой строкой. Если содержимое нужно дважды, его сохраняют в переменную или возвращают позицию через seek(0).
§4read(size)
С аргументом метод читает не больше указанного числа символов и сдвигает позицию ровно на столько.
with open("demo.txt", encoding="utf-8") as file: print(repr(file.read(5))) print(repr(file.read(5)))
'перва' 'я стр'
Границы слов метод не учитывает — он отсчитывает символы. Если до конца файла осталось меньше запрошенного, вернётся столько, сколько есть.
§5Чтение порциями
Отсюда стандартный приём для больших файлов: читать блоками в цикле, пока не вернётся пустая строка.
with open("demo.txt", encoding="utf-8") as file: while True: chunk = file.read(10) if not chunk: break print(repr(chunk))
'первая стр' 'ока\nвторая' ' строка\nтр' 'етья строк' 'а\n'
Проверка if not chunk опирается на истинность из главы 3.16: пустая строка ложна. Так файл любого размера обрабатывается при фиксированном расходе памяти.
§6Символы, а не байты
В текстовом режиме аргумент size задаётся в символах. Это важно для кириллицы, где символ занимает два байта.
| Режим | read(5) вернёт | tell() покажет |
|---|---|---|
| текстовый | 5 символов | число байтов |
двоичный "rb" | 5 байтов | число байтов |
Несовпадение единиц в одной строке таблицы — источник путаницы при работе с позицией, и глава 8.11 разбирает его отдельно.
§7Пустой файл и конец файла
Ни то ни другое ошибкой не считается — просто возвращается пустая строка.
with open("empty.txt", "w", encoding="utf-8"): pass with open("empty.txt", encoding="utf-8") as file: print(repr(file.read()))
''
Пустая строка — универсальный признак «читать больше нечего». Именно на нём построен цикл из §5.
§8Переводы строк в результате
read() возвращает текст как есть, вместе с символами \n. Обычный print() их выведет как настоящие переносы, и структура станет незаметной.
with open("demo.txt", encoding="utf-8") as file: content = file.read() print(content) print(repr(content))
первая строка вторая строка третья строка 'первая строка\nвторая строка\nтретья строка\n'
Пустая строка после третьей — след завершающего \n. При отладке файлов repr() из главы 5.2 незаменим.
§9Разбить на строки
Если нужен список строк, прочитанное разбивают методом splitlines() из главы 5.10.
with open("demo.txt", encoding="utf-8") as file: lines = file.read().splitlines() print(lines)
['первая строка', 'вторая строка', 'третья строка']
Именно splitlines(), а не split("\n"): последний оставил бы лишний пустой элемент из-за завершающего перевода. Есть и готовый метод readlines() — глава 8.10, — но он сохраняет символы \n.
§10Когда read() не подходит
Метод загружает файл в память целиком. Для файла в несколько гигабайт это означает несколько гигабайт оперативной памяти.
| Задача | Способ |
|---|---|
| небольшой файл целиком | read() |
| файл любого размера, построчно | перебор for line in file |
| файл любого размера, блоками | read(size) в цикле |
| первая строка | readline() |
Вторая строка — самый частый вариант в реальном коде: файловый объект сам по себе итерируемый и выдаёт строки по одной, не загружая всё сразу.
with open("demo.txt", encoding="utf-8") as file: for line in file: print(repr(line))
'первая строка\n' 'вторая строка\n' 'третья строка\n'
§11Двоичное чтение
В режиме "rb" метод возвращает bytes, а не строку.
with open("demo.txt", "rb") as file: print(file.read(4))
b'\xd0\xbf\xd0\xb5'
Двоичное чтение опасно для текста: если прочитать нечётное число байтов, символ разорвётся пополам, и декодировать такой кусок будет нечем. Для текстовых файлов берут текстовый режим.
§12Ошибки при чтении
| Ситуация | Исключение |
|---|---|
| файла нет | FileNotFoundError |
| нет прав на чтение | PermissionError |
файл открыт в режиме "w" | UnsupportedOperation |
| двоичные данные в текстовом режиме | UnicodeDecodeError |
| файл уже закрыт | ValueError |
Первые три наследуют от OSError из главы 8.3, четвёртая — от ValueError через UnicodeError. Значит, except OSError покроет проблемы доступа, но не проблемы кодировки — их ловят отдельно.
§13Частые ошибки
| Что написано | Что произойдёт | Как правильно |
|---|---|---|
второй read() того же файла | вернётся пустая строка | сохранить результат или seek(0) |
read() для файла в гигабайты | всё окажется в памяти | перебор for line in file |
file.read() после блока with | ValueError: файл закрыт | читать внутри блока |
read().split("\n") | лишний пустой элемент в конце | splitlines() |
ждать read(5) ровно пять байт | в текстовом режиме это символы | для байтов — режим "rb" |
читать двоичный файл без "b" | UnicodeDecodeError | режим "rb" |
| ждать исключение в конце файла | вернётся пустая строка | проверять if not chunk |
§14Проверьте себя
Почему второй read() возвращает пустую строку?
После первого чтения позиция стоит в конце файла. Ошибки нет — просто читать больше нечего.
В чём измеряется аргумент read(size)?
В текстовом режиме — в символах, в двоичном — в байтах. При этом tell() всегда показывает байты.
Как понять, что файл закончился?
По пустой строке в результате. Исключения при достижении конца не возникает.
Почему splitlines() лучше, чем split("\n")?
Файлы обычно заканчиваются переводом строки, и split() добавил бы лишний пустой элемент.
Когда read() использовать не стоит?
Когда файл большой: метод загружает его в память целиком. Для таких случаев есть построчный перебор и чтение блоками.
Что вернёт read() в режиме "rb"?
Объект bytes, а не строку. Кодировка при этом не применяется.
§15Шпаргалка
text = file.read()chunk = file.read(1024)file.read().splitlines()for line in file:file.seek(0)if not chunk: breakИтог главы
read() без аргумента возвращает весь файл одной строкой, с аргументом — не больше указанного числа символов. Всё поведение объясняется позицией: она сдвигается при чтении, поэтому повторный вызов возвращает пустую строку, а не содержимое заново. Конец файла — не ошибка, а пустая строка, и на этом строится чтение блоками. Для больших файлов вместо read() берут построчный перебор, который не загружает всё в память.