Справочник по Python · модуль 8 · исключения и файлы
Глава 8.13
Режим x:
создание файла
Режим создаёт новый файл и отказывается работать, если такой уже есть. Это защита от того самого сценария главы 8.6, где "w" молча стирает существующие данные: вместо тихой потери — явное исключение.
- Категория
- Файлы
- Уровень
- Базовый
- Связанные темы
- Режимы открытия, исключения
- Зачем это знать
- Гарантированно не перезаписать существующий файл
§1Проблема режима w
Глава 8.6 показала: open(path, "w") стирает содержимое в момент открытия. Если программа создаёт файл отчёта, а такой файл уже есть, прежние данные исчезнут — без предупреждения и без возможности вернуть.
Иногда это и нужно. Но когда файл должен быть именно новым, требуется другое поведение: не молчаливая перезапись, а отказ.
§2Как работает режим x
Режим "x" — от exclusive creation, «исключительное создание». Он создаёт файл и открывает его на запись.
with open("newfile.txt", "x", encoding="utf-8") as file: file.write("создан") print(open("newfile.txt", encoding="utf-8").read())
создан
Пока файла нет, режим ведёт себя точно как "w". Разница проявляется во втором запуске.
§3Файл уже существует
with open("newfile.txt", "x", encoding="utf-8") as file: file.write("второй раз")
FileExistsError: [Errno 17] File exists: 'newfile.txt'
Существующее содержимое осталось нетронутым: исключение возникает при открытии, до всякой записи. Именно это и требовалось — потерять данные невозможно.
§4Обработка исключения
FileExistsError — потомок OSError из главы 8.3, и обрабатывается как любое другое исключение.
try: with open("newfile.txt", "x", encoding="utf-8") as file: file.write("данные") except FileExistsError: print("Файл уже существует, перезапись отменена.")
Файл уже существует, перезапись отменена.
Дальше решение принимает программа: предложить другое имя, добавить к имени номер или спросить пользователя.
§5Двоичный вариант
Как и остальные режимы, "x" сочетается с буквой b.
with open("data.bin", "xb") as file: file.write(b"bin") print(open("data.bin", "rb").read())
b'bin'
Есть и форма "x+" — создание с возможностью чтения, по аналогии с "w+" из главы 8.6.
§6Сравнение режимов
| Режим | Файла нет | Файл есть | Смысл |
|---|---|---|---|
"w" | создаёт | стирает содержимое | «мне нужен файл с этим содержимым» |
"a" | создаёт | дописывает в конец | «добавь к тому, что есть» |
"x" | создаёт | FileExistsError | «файл должен быть новым» |
"r" | FileNotFoundError | читает | «файл должен существовать» |
Последние две строки зеркальны: "x" требует отсутствия файла, "r" — его наличия. Оба сообщают о несоответствии исключением, а не молча.
§7Чем лучше проверки exists()
Тот же результат кажется достижимым проверкой перед открытием.
import os между проверкой и открытием
файл может появиться —
if not os.path.exists(path): и тогда он будет стёрт
with open(path, "w") as f:
...
with open(path, "x") as f: проверка и создание —
... одна неделимая операция
Разница не теоретическая: если файл создаёт другая программа или другой процесс той же программы, между проверкой и открытием проходит время, и в этот промежуток файл может появиться. Режим "x" выполняет проверку и создание одним действием на уровне операционной системы, поэтому такого промежутка не возникает.
§8Где применяется
| Задача | Почему "x" |
|---|---|
| создать файл-метку о запуске | вторая копия программы получит ошибку и не запустится |
| сохранить результат под новым именем | случайно не затереть прошлый результат |
| первичная настройка проекта | не испортить существующий конфиг |
| выгрузка с датой в имени | обнаружить повторный запуск за тот же день |
Общий признак: файл создаётся один раз, и его повторное создание — признак ошибки в сценарии работы, о которой лучше узнать.
§9Частые ошибки
| Что написано | Что произойдёт | Как правильно |
|---|---|---|
"x" там, где файл перезаписывается регулярно | второй запуск упадёт | режим "w" |
"x" без обработки исключения | программа остановится при повторном запуске | try / except FileExistsError |
проверка os.path.exists() перед "w" | между проверкой и записью файл может появиться | режим "x" |
ждать дозаписи от "x" | к существующему файлу он не откроется вовсе | режим "a" |
ловить FileNotFoundError вместо FileExistsError | исключение не будет перехвачено | они противоположны по смыслу |
§10Проверьте себя
Что делает режим "x", если файл уже есть?
Вызывает FileExistsError при открытии, не изменяя существующий файл.
Чем "x" отличается от "w"?
Оба создают файл, если его нет. Но "w" стирает существующий, а "x" отказывается работать.
Почему "x" надёжнее проверки os.path.exists()?
Проверка и создание выполняются одной операцией, поэтому файл не может появиться в промежутке между ними.
От какого класса наследует FileExistsError?
От OSError — как и остальные ошибки работы с файлами из главы 8.3.
Можно ли использовать "x" для двоичных файлов?
Да, режим записывается как "xb". Есть и "x+" для создания с возможностью чтения.
§11Шпаргалка
open(path, "x", encoding="utf-8")open(path, "xb")except FileExistsError:open(path, "w")open(path, "a")Итог главы
Режим "x" создаёт файл только при его отсутствии, а иначе вызывает FileExistsError — существующие данные при этом не страдают. Он зеркален режиму "r", который требует, чтобы файл был. Главное его преимущество перед проверкой os.path.exists() в том, что проверка и создание выполняются одной неделимой операцией, и файл не может появиться в промежутке. Этим завершается разбор режимов открытия и всего модуля о файлах.