Как открыть и закрыть файл в Python
Открытие и закрытие файла в Python выполняются функцией open() и методом close(), а надежнее всего через конструкцию with, которая закрывает файл автоматически. В статье разобраны параметры open(), пути к файлу, режимы, ошибки при открытии и три способа гарантированно закрыть файл.

Содержание статьи
Функция open() и ее параметры
open() принимает путь к файлу и возвращает файловый объект, через который потом идут чтение и запись. Обязателен только первый аргумент, остальные имеют значения по умолчанию.
f = open('data.txt', mode='r', encoding='utf-8')
print(type(f)) # <class '_io.TextIOWrapper'>
print(f.name, f.mode, f.closed) # data.txt r False
f.close()
Самые нужные параметры:
file- путь к файлу строкой или объектом Path;mode- режим открытия, по умолчанию'r';encoding- кодировка текста, для кириллицы указывайте'utf-8'явно;errors- что делать с байтами, которые не декодируются:'strict','ignore','replace';newline- как обрабатывать переносы строк, для модуля csv передают пустую строку;buffering- размер буфера, 0 разрешен только в бинарном режиме.
Полное описание есть в официальной документации open().
Абсолютный и относительный путь
Абсолютный путь начинается от корня диска: C:/projects/data.txt в Windows или /home/user/data.txt в Linux. Относительный путь вроде data/report.txt отсчитывается от текущей рабочей папки процесса, а не от папки, где лежит скрипт. Из-за этого программа, которая работает в IDE, может не найти файл при запуске из другого каталога.
В Windows обратные слеши в обычной строке воспринимаются как начало escape-последовательности: в 'C:\new\table.txt' фрагменты \n и \t превратятся в перенос и табуляцию. Используйте прямые слеши, сырую строку r'C:\new\table.txt' или модуль pathlib.
from pathlib import Path
base = Path(__file__).resolve().parent # папка скрипта
config = base / 'config' / 'settings.ini'
with open(config, encoding='utf-8') as f:
print(f.readline())
Такой путь не зависит от того, откуда запущена программа. Подробнее о путях рассказано в статье о модуле pathlib, а текущую папку можно узнать функцией os.getcwd() из модуля os.
Режимы открытия файла
Режим задается строкой из одной или нескольких букв. Первая буква определяет основное действие, дополнительные уточняют тип данных и доступ.
| Символ | Значение |
|---|---|
| r | Чтение. Файл должен существовать |
| w | Запись. Файл создается, а существующий очищается |
| a | Дозапись в конец. Файл создается при отсутствии |
| x | Создание нового файла, ошибка, если он уже есть |
| b | Бинарный режим, данные типа bytes |
| t | Текстовый режим (по умолчанию) |
| + | Добавляет к режиму второе действие: r+ читает и пишет |
Комбинации пишут слитно: 'rb', 'wb', 'a+'. Буквы b и t вместе указывать нельзя. Режим x полезен, когда нужно гарантированно не затереть чужой файл. Работа с байтами подробно описана в статье про бинарные файлы.
Ошибки при открытии
open() выбрасывает исключение, если файл нельзя открыть в указанном режиме. Чаще всего встречаются:
FileNotFoundError- файла или папки по пути нет (только для режимов r и r+, а также если не существует родительская папка);PermissionError- нет прав доступа или файл заблокирован другой программой, например открыт в Excel;IsADirectoryError- по пути находится папка, а не файл;FileExistsError- файл уже существует, а открыт в режиме x.
Все они наследуются от OSError, поэтому при желании их ловят одним блоком.
try:
f = open('missing.txt', encoding='utf-8')
except FileNotFoundError:
print('Файл не найден, создаю пустой')
open('missing.txt', 'w', encoding='utf-8').close()
except OSError as err:
print('Не удалось открыть:', err)
else:
print(f.read())
f.close()
Зачем закрывать файл
Открытый файл занимает дескриптор операционной системы, а их число на процесс ограничено. Кроме того, при записи данные сначала копятся в буфере в памяти и сбрасываются на диск только при закрытии или вызове flush(). Если программа аварийно завершится до закрытия, последние строки могут не попасть в файл. В Windows незакрытый файл к тому же нельзя удалить или переименовать из другой программы.
Метод close() сбрасывает буфер и освобождает ресурсы. Повторный вызов close() безопасен, а вот чтение или запись после закрытия дают ValueError: I/O operation on closed file. Проверить состояние можно атрибутом closed.
f = open('test.txt', 'w', encoding='utf-8')
f.write('hello world')
f.close() # без скобок метод не вызовется
print(f.closed) # True
Частая опечатка: f.close без скобок. Это просто обращение к методу, файл при этом остается открытым.
Три способа гарантированно закрыть файл
Вызов close() в конце кода не сработает, если раньше произошло исключение. Поэтому закрытие нужно привязать к выходу из блока при любом исходе.
Блок try/finally
Код в finally выполняется всегда, даже при ошибке внутри try. Открытие ставят до try: если open() упадет, закрывать будет нечего.
f = open('test.txt', 'w', encoding='utf-8')
try:
f.write('hello world')
finally:
f.close()
Конструкция with
Файловый объект является менеджером контекста. При выходе из блока with Python сам вызывает close(), в том числе при исключении или return. Это рекомендуемый способ, код короче и без лишних уровней вложенности.
with open('test.txt', 'w', encoding='utf-8') as f:
f.write('hello world')
print(f.closed) # True
Несколько файлов в одном with
Через запятую можно открыть сразу несколько файлов, все они закроются при выходе. С Python 3.10 список менеджеров можно взять в круглые скобки и переносить по строкам.
with (
open('input.txt', encoding='utf-8') as src,
open('output.txt', 'w', encoding='utf-8') as dst,
):
for line in src:
dst.write(line.upper())
Что делать с файлом после открытия, разобрано в статье о чтении и записи файлов.
Частые вопросы
Ответы на вопросы об открытии и закрытии файлов.
Нужно ли вызывать close() внутри with?
Нет. Файл закрывается автоматически при выходе из блока. Явный close() внутри with ничего не сломает, но он лишний.
Что будет, если не закрыть файл?
В CPython объект обычно закроется, когда на него не останется ссылок, или при завершении программы. Но на это нельзя полагаться: данные из буфера могут потеряться, а в долгоживущих программах закончатся дескрипторы.
Почему open() не находит файл, который лежит рядом со скриптом?
Относительный путь считается от рабочей папки, а она может отличаться от папки скрипта. Постройте путь от Path(__file__).parent или укажите абсолютный путь.
Как проверить, существует ли файл перед открытием?
Используйте Path('data.txt').exists() или os.path.exists(). Надежнее сразу открывать и ловить FileNotFoundError: между проверкой и открытием файл могут удалить.