W3docs

Запись и создание файлов в Python

Все способы записи файлов в Python: write(), writelines(), режим append, бинарная запись, pathlib и безопасные паттерны с блоком with.

Запись файлов — одна из самых фундаментальных операций ввода-вывода в Python. Сохраняете ли вы результаты работы программы, конфигурацию, экспортируете данные в CSV или записываете события в лог — вам нужен надёжный способ создавать и обновлять файлы. В этой главе рассматриваются все подходы, которые предоставляет Python: write(), writelines(), режим append, бинарная запись, обработка символов новой строки, кодировка символов, современный API pathlib и паттерны безопасной записи без потери данных.

Открытие файла для записи

Любая операция записи начинается со встроенной функции open(). Второй аргумент — режим — определяет, что происходит при открытии файла:

РежимЗначениеФайл существуетФайл отсутствует
"w"Запись (текст)Усекает (стирает) файлСоздаёт новый файл
"a"Добавление (текст)Перемещает указатель в конецСоздаёт новый файл
"x"Исключительное созданиеВызывает FileExistsErrorСоздаёт новый файл
"wb"Запись (бинарный)Усекает файлСоздаёт новый файл
"ab"Добавление (бинарный)Перемещает указатель в конецСоздаёт новый файл
"r+"Чтение + записьОткрывает на местеВызывает FileNotFoundError

Самое важное, что нужно помнить о режиме "w": он молча стирает весь файл перед записью. Если вы хотите только добавить содержимое к существующему файлу, используйте режим "a" (append).

Всегда указывайте параметр encoding при записи текстовых файлов, чтобы ваш код вёл себя одинаково на Windows, macOS и Linux:

file = open("output.txt", "w", encoding="utf-8")

Всегда используйте блок with

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

Оператор with (менеджер контекста) решает все эти проблемы. Python автоматически закрывает файл при выходе из блока — даже если внутри блока возникло исключение.

with open("output.txt", "w", encoding="utf-8") as f:
    f.write("Hello, World!\n")
# File is closed and flushed here — guaranteed

Все примеры в этой главе используют оператор with. Избегайте ручного паттерна open() / close().

Запись текста с помощью write()

file.write(string) записывает переданную строку в файл и возвращает количество записанных символов. Символ новой строки не добавляется автоматически — вы должны включить \n самостоятельно.

Запись одной строки в новый файл

with open("greeting.txt", "w", encoding="utf-8") as f:
    chars_written = f.write("Hello, World!\n")
    print(chars_written)   # 14

Запись нескольких строк многократными вызовами write()

with open("poem.txt", "w", encoding="utf-8") as f:
    f.write("Roses are red,\n")
    f.write("Violets are blue,\n")
    f.write("Python is great,\n")
    f.write("And so are you.\n")

Каждый вызов write() добавляет данные в файл начиная с текущей позиции. Файл записывается заново (всё предыдущее содержимое удаляется), поскольку использован режим "w".

Запись нескольких строк с помощью writelines()

file.writelines(iterable) принимает любой итерируемый объект строк — список, генератор или кортеж — и записывает каждый элемент последовательно. Как и write(), он не добавляет символы новой строки между элементами.

Запись списка строк

lines = [
    "First line\n",
    "Second line\n",
    "Third line\n",
]

with open("lines.txt", "w", encoding="utf-8") as f:
    f.writelines(lines)

Если исходные данные не содержат \n, добавьте его перед записью:

data = ["Alice", "Bob", "Charlie"]

with open("names.txt", "w", encoding="utf-8") as f:
    f.writelines(name + "\n" for name in data)

Выражение-генератор name + "\n" for name in data эффективно по памяти: Python создаёт каждую строку по требованию, не строя весь список в памяти заранее.

write() против writelines() — когда что использовать

write()writelines()
Входные данныеОдна строкаЛюбой итерируемый объект строк
Символы новой строкиВы управляете каждым \nВы управляете каждым \n
Лучше всего дляПостепенного формирования выводаЗаписи готовой последовательности за один раз

Создание файла, который не должен существовать

Используйте режим "x" (исключительное создание), если хотите, чтобы Python создал новый файл и завершился с ошибкой, если файл уже существует. Это предотвращает случайную перезапись важных данных.

try:
    with open("config.txt", "x", encoding="utf-8") as f:
        f.write("host=localhost\n")
        f.write("port=8080\n")
except FileExistsError:
    print("config.txt already exists — not overwriting.")

Этот паттерн полезен при генерации уникальных выходных файлов (логов, экспортов, снимков состояния), когда коллизия означает, что что-то пошло не так.

Добавление данных в существующий файл

Открытие файла в режиме "a" перемещает указатель записи в конец файла. Новое содержимое добавляется после существующего; ничего не стирается.

Добавление записи в лог в существующий файл

import datetime

with open("app.log", "a", encoding="utf-8") as f:
    timestamp = datetime.datetime.now().isoformat()
    f.write(f"[{timestamp}] Server started\n")

Если app.log ещё не существует, Python создаёт его. Если он уже существует, новая строка добавляется в конец. При многократном запуске скрипта лог постепенно растёт.

Запись против добавления — выбор правильного режима

  • Используйте "w", когда хотите заменить содержимое файла полностью (сгенерировать свежий отчёт, сохранить новую конфигурацию).
  • Используйте "a", когда хотите добавить к существующему содержимому (ведение лога, накопление результатов за несколько запусков).

Символы новой строки и окончания строк

Текстовый режим Python ("w", "a", "r") транслирует универсальный символ новой строки \n в платформенный разделитель строк при записи:

  • Windows: \n\r\n (CRLF)
  • macOS / Linux: \n остаётся \n (LF)

Обычно это правильное поведение — файлы, записанные на Windows, корректно открываются в Блокноте.

Если нужно принудительно задать конкретное окончание строки независимо от платформы — например, при генерации файлов, которые должны читаться конкретной системой, — передайте параметр newline:

# Force Unix-style LF on all platforms (e.g. for Linux-target files)
with open("unix_file.txt", "w", encoding="utf-8", newline="\n") as f:
    f.write("line one\n")
    f.write("line two\n")

# Preserve line endings exactly as given (no translation at all)
with open("raw.txt", "w", encoding="utf-8", newline="") as f:
    f.write("line one\r\n")
    f.write("line two\n")

Кодировка символов

Всегда указывайте encoding= при записи текстовых файлов. Использование платформенной кодировки по умолчанию рискует создать файлы, которые нельзя прочитать на других системах.

Рекомендуемые кодировки для распространённых сценариев:

КодировкаКогда использовать
"utf-8"Общего назначения; работает для всех языков; по умолчанию для большинства Python-проектов
"utf-8-sig"UTF-8 с BOM — полезна для файлов, которые будут открываться в Excel на Windows
"latin-1"Устаревшие западноевропейские файлы
"cp1252"Windows ANSI текст

Запись файла в кодировке UTF-8

with open("international.txt", "w", encoding="utf-8") as f:
    f.write("English: Hello\n")
    f.write("Japanese: こんにちは\n")
    f.write("Arabic: مرحبا\n")

Запись бинарных файлов

Откройте файл в режиме "wb" (запись бинарных данных), чтобы записывать необработанные байты вместо строк. Бинарный режим необходим для изображений, аудио, сжатых архивов, исполняемых файлов и любых нетекстовых данных. Не указывайте encoding в бинарном режиме.

Запись байтов в бинарный файл

data = bytes([0x89, 0x50, 0x4E, 0x47])  # PNG magic bytes

with open("header.bin", "wb") as f:
    f.write(data)
    print(f.write(b"\r\n\x1a\n"))   # 4

Копирование бинарного файла

with open("photo.jpg", "rb") as src:
    content = src.read()

with open("photo_backup.jpg", "wb") as dst:
    dst.write(content)

Для больших бинарных файлов читайте и записывайте по частям, чтобы не загружать весь файл в память:

CHUNK = 65536  # 64 KB

with open("large.bin", "rb") as src, open("large_copy.bin", "wb") as dst:
    while True:
        chunk = src.read(CHUNK)
        if not chunk:
            break
        dst.write(chunk)

Обработка ошибок при записи

Скрипт производственного качества всегда предусматривает возможные ошибки записи файла.

Обработка распространённых ошибок записи

try:
    with open("/etc/protected.txt", "w", encoding="utf-8") as f:
        f.write("data\n")
except PermissionError:
    print("Error: you do not have write permission for this file.")
except FileNotFoundError:
    print("Error: one or more directories in the path do not exist.")
except IsADirectoryError:
    print("Error: the path points to a directory, not a file.")
except OSError as e:
    print(f"OS error: {e}")

Распространённые исключения, с которыми вы столкнётесь:

ИсключениеКогда возникает
PermissionErrorУ процесса нет прав на запись
FileNotFoundErrorПромежуточный каталог в пути не существует
FileExistsErrorРежим "x" и файл уже существует
IsADirectoryErrorПуть указывает на каталог
OSErrorДиск заполнен, ошибка сетевой файловой системы и другие проблемы уровня ОС

Смотрите Python Try Except — полное руководство по обработке исключений.

Безопасная запись файлов (паттерн атомарной записи)

Обычный open("file.txt", "w") небезопасен для критически важных данных: если ваш скрипт аварийно завершится или будет прерван в процессе записи, файл останется в частично записанном, повреждённом состоянии. Стандартное решение — атомарная запись: сначала запишите во временный файл, затем переименуйте его поверх целевого.

import os
import tempfile

def write_file_safely(path, content, encoding="utf-8"):
    """Write content to path atomically using a temp file + rename."""
    dir_name = os.path.dirname(os.path.abspath(path)) or "."
    # Write to a temp file in the same directory (same filesystem = atomic rename)
    fd, tmp_path = tempfile.mkstemp(dir=dir_name)
    try:
        with os.fdopen(fd, "w", encoding=encoding) as f:
            f.write(content)
        os.replace(tmp_path, path)   # atomic on POSIX; best-effort on Windows
    except Exception:
        os.unlink(tmp_path)          # clean up if something went wrong
        raise

write_file_safely("important.txt", "critical data\n")

os.replace() (Python 3.3+) атомарно заменяет файл назначения на POSIX-системах: читатели видят либо старый файл, либо новый, но никогда — частичную запись.

Запись файлов с помощью pathlib

pathlib.Path (введён в Python 3.4) предоставляет лаконичный объектно-ориентированный API. Для простых единовременных записей Path.write_text() и Path.write_bytes() читаются лучше, чем open().

Path.write_text()

from pathlib import Path

Path("output.txt").write_text("Hello from pathlib!\n", encoding="utf-8")

write_text() открывает файл в режиме "w", записывает строку и закрывает файл — всё за один вызов. Он всегда перезаписывает файл. Эквивалента для добавления не существует; для добавления используйте open() с режимом "a".

Path.write_bytes()

from pathlib import Path

Path("data.bin").write_bytes(b"\x00\x01\x02\x03")

Построение путей с помощью pathlib

pathlib также упрощает безопасное построение путей без конкатенации строк:

from pathlib import Path

output_dir = Path("results")
output_dir.mkdir(exist_ok=True)          # create the directory if needed

report_path = output_dir / "report.txt"
report_path.write_text("Run complete.\n", encoding="utf-8")

print(report_path)         # results/report.txt
print(report_path.exists())  # True

Оператор / на объектах Path соединяет сегменты пути — нет необходимости в os.path.join().

Практический пример: запись CSV-отчёта

Следующий полный пример записывает список записей в CSV-файл, используя только встроенные инструменты (без модуля csv), демонстрируя несколько концепций из этой главы вместе.

from pathlib import Path
import datetime

def write_csv_report(path, headers, rows):
    """Write a simple CSV file with a header row."""
    with open(path, "w", encoding="utf-8", newline="") as f:
        f.write(",".join(headers) + "\n")
        for row in rows:
            f.write(",".join(str(v) for v in row) + "\n")

records = [
    ("Alice", 30, "Engineering"),
    ("Bob", 25, "Marketing"),
    ("Charlie", 35, "Finance"),
]

output = Path("staff_report.txt")
write_csv_report(output, ["Name", "Age", "Department"], records)

print(output.read_text(encoding="utf-8"))

Ожидаемый вывод:

Name,Age,Department
Alice,30,Engineering
Bob,25,Marketing
Charlie,35,Finance

Обратите внимание: newline="" передаётся в open(), чтобы Python не применял двойную трансляцию окончаний строк внутри CSV-строк — это соответствует рекомендации в документации модуля csv Python.

Для всего более сложного (кавычки, диалекты, граничные случаи Unicode) используйте встроенный модуль Python CSV.

Краткий справочник

ЦельПаттерн кода
Создать или перезаписать файлopen("f.txt", "w", encoding="utf-8")
Добавить данные в файлopen("f.txt", "a", encoding="utf-8")
Создать только если новогоopen("f.txt", "x", encoding="utf-8")
Записать бинарные данныеopen("f.bin", "wb")
Записать одну строкуf.write("text\n")
Записать список строкf.writelines(lines)
Единовременная запись текстаPath("f.txt").write_text("...", encoding="utf-8")
Единовременная запись байтовPath("f.bin").write_bytes(b"...")
Безопасная / атомарная записьЗапись во временный файл, затем os.replace()

Связанные главы

  • Python File Handling — режимы открытия, параметры open() и оператор with
  • Python Read Filesread(), readline(), readlines(), итерация по строкам и seek()
  • Python Delete Files — безопасное удаление файлов и каталогов
  • Python Try Except — обработка исключений в Python
  • Python CSV — чтение и запись CSV-файлов с модулем csv
  • Python JSON — сериализация данных в JSON-файлы
Was this page helpful?