W3docs

Работа с файлами в Python: полное руководство

Работа с файлами в Python: открытие в разных режимах, чтение и запись данных, pathlib, обработка ошибок и управление позицией в файле.

Работа с файлами позволяет программам постоянно хранить данные и получать их позже. В этой главе рассматриваются все распространённые файловые операции в Python: открытие файлов в различных режимах, чтение и запись данных, навигация внутри файла, задание кодировки символов и обработка ошибок, возникающих в реальном коде.

Функция open()

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

file_object = open(file, mode="r", encoding=None)
  • file — путь к файлу (string или объект pathlib.Path).
  • mode — режим открытия файла (см. таблицу ниже).
  • encoding — кодировка текста, например "utf-8". Всегда указывайте её для текстовых файлов, чтобы код работал одинаково на любой операционной системе.

Режимы открытия файлов

РежимЗначениеСоздаёт файл?Очищает существующий файл?
"r"Чтение (по умолчанию)НетНет
"w"ЗаписьДаДа
"a"ДобавлениеДаНет
"x"Эксклюзивное созданиеОшибка, если файл существует
"r+"Чтение и записьНетНет
"b"Двоичный режим (в сочетании с другими, например "rb")
"t"Текстовый режим (по умолчанию, в сочетании с другими, например "rt")

Всегда используйте with для открытия файлов

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

Безопасное открытие файла с помощью with

with open("notes.txt", "r", encoding="utf-8") as f:
    contents = f.read()
# File is automatically closed here

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

Чтение файлов

Python предоставляет несколько способов считывания содержимого файла.

Чтение всего файла с помощью read()

read() возвращает полное содержимое файла в виде единой строки.

Чтение всего файла

with open("notes.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)

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

Чтение фиксированного числа символов

Передайте целое число в read(n), чтобы прочитать не более n символов.

Чтение первых 20 символов

with open("notes.txt", "r", encoding="utf-8") as f:
    chunk = f.read(20)
    print(repr(chunk))

Чтение строки за строкой с помощью readline()

readline() возвращает следующую строку вместе с завершающим \n, или пустую string в конце файла.

Построчное чтение файла с помощью readline()

with open("notes.txt", "r", encoding="utf-8") as f:
    line = f.readline()
    while line:
        print(line, end="")   # line already contains '\n'
        line = f.readline()

Итерация по строкам (наиболее идиоматичный способ)

Прямая итерация по объекту файла — наиболее эффективный по памяти подход для построчного чтения.

Итерация по строкам

with open("notes.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line, end="")

Чтение всех строк в список с помощью readlines()

readlines() возвращает список, где каждый элемент — одна строка (включая символ новой строки).

Чтение всех строк в список

with open("notes.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()

print(lines[0])   # first line
print(len(lines)) # total number of lines

Используйте readlines(), когда нужен произвольный доступ к конкретным строкам по индексу. Для последовательной обработки предпочтительнее паттерн for line in f.

Запись файлов

Режим записи ("w")

Режим записи создаёт файл, если он не существует, и очищает его (обнуляет содержимое), если он существует.

Запись текста в файл

with open("output.txt", "w", encoding="utf-8") as f:
    f.write("Line one\n")
    f.write("Line two\n")

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

writelines() принимает итерируемый объект из строк. Символы новой строки не добавляются автоматически.

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

lines = ["apple\n", "banana\n", "cherry\n"]

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

Режим добавления ("a")

Режим добавления перемещает позицию записи в конец файла перед каждой записью, поэтому существующее содержимое никогда не перезаписывается.

Добавление записи в журнал

import datetime

entry = f"{datetime.date.today()} — task complete\n"

with open("log.txt", "a", encoding="utf-8") as f:
    f.write(entry)

При каждом запуске этого скрипта в log.txt добавляется новая строка без изменения предыдущих записей.

Режим эксклюзивного создания ("x")

Используйте "x", когда нужно создать новый файл с гарантией того, что существующий не будет перезаписан. Python вызывает FileExistsError, если файл уже существует.

Создание файла только в случае его отсутствия

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

Позиция в файле: seek() и tell()

Объекты файлов поддерживают внутренний указатель позиции, который перемещается по мере чтения или записи. Этот указатель можно проверять и изменять.

  • tell() — возвращает текущую позицию в байтах.
  • seek(offset, whence=0) — перемещает указатель. whence=0 (по умолчанию) — от начала, 1 — от текущей позиции, 2 — от конца.

Возврат в начало с помощью seek(0)

with open("notes.txt", "r", encoding="utf-8") as f:
    first_pass = f.read()
    f.seek(0)              # go back to the start
    second_pass = f.read()

print(first_pass == second_pass)  # True

seek() особенно полезен в режиме "r+" (чтение-запись), когда нужно прочитать раздел, а затем перезаписать его в рамках того же открытого файла.

Работа с двоичными файлами

Откройте файл в двоичном режиме, добавив "b" к строке режима ("rb", "wb", "ab"). Двоичный режим возвращает необработанные байты вместо строк, что необходимо для изображений, аудио, сжатых архивов и других нетекстовых данных.

Копирование файла в двоичном режиме

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

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

Не указывайте encoding при использовании двоичного режима — Python вызовет ValueError, если вы это сделаете.

Обработка ошибок

Файловые операции могут завершаться неудачей предсказуемым образом. Оборачивание их в блоки try/except делает скрипты надёжными.

Обработка распространённых ошибок файлов

try:
    with open("data.txt", "r", encoding="utf-8") as f:
        content = f.read()
except FileNotFoundError:
    print("Error: the file does not exist.")
except PermissionError:
    print("Error: you do not have permission to read this file.")
except OSError as e:
    print(f"OS error: {e}")

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

ИсключениеКогда возникает
FileNotFoundErrorЧтение файла, которого не существует
FileExistsErrorСоздание файла в режиме "x", когда он уже существует
PermissionErrorОтсутствие прав на чтение/запись
IsADirectoryErrorПопытка открыть директорию как файл
UnicodeDecodeErrorБайты файла не соответствуют указанной кодировке

Современная альтернатива: pathlib

В Python 3.4 появился pathlib.Path — объектно-ориентированный подход к путям файловой системы. Объекты Path seamlessly работают с open() и предоставляют собственные удобные методы read_text() / write_text().

Чтение файла с помощью pathlib

from pathlib import Path

content = Path("notes.txt").read_text(encoding="utf-8")
print(content)

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

from pathlib import Path

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

read_text() и write_text() открывают и закрывают файл за вас, делая разовые операции чтения и записи очень лаконичными. Используйте open() с блоком with, когда нужен более тонкий контроль — например, чтение файла по частям или использование seek().

Переименование и перемещение файлов

Для переименования или перемещения файла используйте os.rename() при переименовании в пределах одной файловой системы или shutil.move(), когда нужно переместить между файловыми системами.

Переименование файла с помощью os.rename()

import os

os.rename("old_name.txt", "new_name.txt")

Перемещение файла с помощью shutil.move()

import shutil

shutil.move("report.txt", "archive/report.txt")

shutil.move() работает даже когда источник и назначение находятся на разных дисках; os.rename() в этом случае вызывает OSError.

Проверка существования файла

Перед открытием файла для чтения может потребоваться убедиться, что он существует. Используйте os.path.exists() или эквивалент из pathlib.

Проверка существования с помощью os.path

import os

if os.path.exists("data.txt"):
    print("File found.")
else:
    print("File not found.")

Проверка существования с помощью pathlib

from pathlib import Path

p = Path("data.txt")
if p.exists():
    print("File found.")

Обратите внимание, что os.path.exists() и Path.exists() могут возвращать устаревшие результаты в многопоточных или многопроцессных программах. В таких случаях предпочтительнее просто вызвать open() и перехватить FileNotFoundError.

Сводка ключевых функций

ОперацияПодход через os / shutilПодход через pathlib
Открыть и прочитатьopen(path, "r")Path(path).read_text()
Открыть и записатьopen(path, "w")Path(path).write_text()
Проверить существованиеos.path.exists(path)Path(path).exists()
Переименоватьos.rename(src, dst)Path(src).rename(dst)
Переместитьshutil.move(src, dst)Path(src).rename(dst) (та же ФС)
Удалитьos.remove(path)Path(path).unlink()

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

Was this page helpful?