Файлы — это просто строки с путём
Большинству программ рано или поздно нужно читать или писать файл — конфиги, пользовательские данные, логи, CSV-экспорты, маленькие кэши. Python делает это просто одной встроенной функцией open() плюс блоком with, чтобы всё аккуратно закрывалось.
Пройдёмся по типичным случаям.
Чтение файла целиком
Самое простое чтение:
with open("notes.txt") as f:
contents = f.read()
print(contents)
open("notes.txt") открывает файл на чтение (режим по умолчанию). Блок with означает, что Python закроет файл при выходе из блока — даже если случится исключение. После закрытия f использовать уже нельзя; текст живёт в contents.
contents — одна строка, содержащая весь файл. Нормально для маленьких; плохо для лога на 2 ГБ.
Чтение построчно
Для больших файлов итерируй, не загружая всё в память:
with open("big.log") as f:
for line in f:
if "ERROR" in line:
print(line.strip())
Каждая итерация даёт строку вместе с перевод строки в конце — поэтому .strip() так часто всплывает. Если хочется именно список строк — f.readlines(), но обычно прямой итерации достаточно.
Запись в файл
Для записи передай режим вторым аргументом:
with open("output.txt", "w") as f:
f.write("first line\n")
f.write("second line\n")
Два момента:
"w"перезаписывает. Еслиoutput.txtуже существовал, его содержимое исчезает в моментopen.- Переводы строк ты ставишь сам.
f.write("hello")пишет ровно эти пять символов — без перевода строки в конце.
Для append-а вместо перезаписи:
with open("output.txt", "a") as f:
f.write("another line\n")
Несколько строк разом — writelines:
lines = ["a\n", "b\n", "c\n"]
with open("letters.txt", "w") as f:
f.writelines(lines)
Правило то же: переводы ставишь ты.
print в файл
У print есть аргумент file — простой способ писать без ручных переводов строк:
with open("log.txt", "w") as f:
print("started", file=f)
print("finished", file=f)
Каждый print пишет аргументы и добавляет перевод строки в конце. Для неформального вывода часто самая приятная форма.
Текстовый и бинарный режимы
По умолчанию open — в текстовом режиме. Python декодирует байты в строки (по умолчанию UTF-8 на современных платформах) и обрабатывает перевод строк.
Для картинок, PDF, скомпилированных файлов или чего-то, что не текст, открывай в бинарном режиме, добавив "b":
with open("image.png", "rb") as f:
data = f.read()
print(len(data)) # number of bytes
with open("image_copy.png", "wb") as f:
f.write(data)
В бинарном режиме ты получаешь объект bytes, а не str, и Python не трогает переводы строк.
Указание кодировки
Для текстовых файлов будь явным с кодировкой. UTF-8 почти всегда правильный выбор в 2026 году:
with open("notes.txt", encoding="utf-8") as f:
contents = f.read()
Если имеешь дело с легаси-файлами из Windows-окружения, можешь встретить cp1252 или latin-1. Ошибёшься с угадыванием — получишь кракозябры или UnicodeDecodeError.
pathlib: современный способ работать с путями
Модуль pathlib из стандартной библиотеки даёт более эргономичный API по сравнению с голыми строками:
from pathlib import Path
path = Path("notes.txt")
# Simple read and write.
contents = path.read_text(encoding="utf-8")
path.write_text("new contents\n", encoding="utf-8")
# Build paths without worrying about / vs \.
data_dir = Path("data")
log_path = data_dir / "today.log"
print(log_path)
print(log_path.exists())
print(log_path.suffix) # ".log"
print(log_path.stem) # "today"
print(log_path.parent) # "data"
Path.read_text() и write_text() — ярлыки для паттерна with open(...) as f, когда хочется прочитать или записать всё разом. Для построчной итерации всё ещё используешь open или path.open().
Маленький пример от начала до конца
Читаем список из файла, фильтруем и пишем результат в другой файл:
from pathlib import Path
source = Path("items.txt")
destination = Path("filtered.txt")
items = source.read_text().splitlines()
kept = [item for item in items if item and not item.startswith("#")]
destination.write_text("\n".join(kept) + "\n")
print(f"Kept {len(kept)} items out of {len(items)}")
splitlines() — построчный компаньон join. Разбивает по переводам строк, не сохраняя их — удобно, когда ты всё равно собираешься собирать куски обратно.
Когда что-то пошло не так
Открытие несуществующего файла поднимает FileNotFoundError. Попытка прочесть файл без прав — PermissionError. Оба — наследники OSError, который наследник Exception — о правильной обработке исключений поговорим на следующей странице.
А пока — короткий превью того, как выглядит обработка ошибок:
from pathlib import Path
path = Path("maybe.txt")
try:
contents = path.read_text()
except FileNotFoundError:
print("File doesn't exist — starting fresh.")
contents = ""
print(repr(contents))
Ключевые привычки
- Всегда используй
with open(...)вместо гологоopen+ ручного закрытия. - Всегда передавай
encoding=для текстовых файлов; UTF-8 по умолчанию. - Большие файлы итерируй построчно; не делай
.read()целиком. - Для путей и типовых чтений/записей —
pathlib: сэкономит много строковой гимнастики.
Дальше — JSON. Большинство текстовых файлов в реальности не простой текст, а структурированные данные, и самая частая форма — JSON. Те же привычки с with open(...) перенесутся напрямую.
Часто задаваемые вопросы
Как прочитать файл в Python?
Используй open() вместе с with — тогда файл автоматически закрывается, когда ты закончил. with open('file.txt') as f: contents = f.read() прочитает файл целиком в строку. Построчно — итерируй сам объект файла: for line in f:.
В чём разница между режимами 'r', 'w' и 'a'?
'r' — чтение (по умолчанию). 'w' — запись: создаёт файл или обрезает его, если существовал. 'a' — append: дописывает в конец без стирания. Добавь 'b' для бинарного режима или '+' для чтения+записи.
Почему лучше использовать with open, а не голый open?
with open, а не голый open?with гарантирует закрытие файла, даже если по ходу случится ошибка. Без with нужно самому вызывать .close() и не забывать об этом в ветвях ошибок. with безопаснее и короче.