Как работать с файлами в Python: режимы, методы, обработка исключений

Раздел: Работа с файлами -> Чтение и запись файлов

Чтение и запись файлов в Python: базовые методы и варианты

Работа с файлами в Python строится вокруг функции open. Она возвращает файловый объект, через который выполняется чтение или запись. Наиболее надежный подход использует контекстный менеджер with, который автоматически закрывает файл даже при исключении.

Основной подход: with open и текстовые режимы

Цель: безопасное чтение и запись текстовых данных. Контекстный менеджер гарантирует закрытие ресурса. Режимы: 'r' чтение, 'w' запись с очисткой, 'a' добавление, 'x' создание, 'b' бинарный, 't' текстовый, '+' обновление.

with open('example.txt', 'w', encoding='utf-8') as f:
    print('Первая строка', file=f)
    print('Вторая строка', file=f)

with open('example.txt', 'r', encoding='utf-8') as f:
    data = f.read()
print(data)

чтение запись файлов python (чтение и запись файлов в python)

Первая строка
Вторая строка

Пояснение: функция open принимает путь, режим и кодировку. Метод write возвращает число записанных символов. Метод read читает весь файл. Контекстный менеджер закрывает файл после выхода из блока.

Как открыть файл вручную, если нужна совместимость со старым кодом?

Вариант с try/finally применяется в коде, где контекстный менеджер недоступен или нужна ручная обработка закрытия. Такой подход требует явного вызова close.

f = open('manual.txt', 'w', encoding='utf-8')
try:
    print('Данные', file=f)
finally:
    f.close()

Пояснение: блок finally гарантирует закрытие даже при ошибке записи.

Ошибка: отсутствие close приводит к утечке файлового дескриптора. Решение: вызов close в finally или переход на with.

Как прочитать файл построчно без загрузки всего содержимого?

Итерация по файловому объекту читает строки по одной. Этот способ подходит для больших файлов и экономит память.

with open('big.txt', 'r', encoding='utf-8') as f:
    for line in f:
        print(line.rstrip())
Ошибка: открытие файла в режиме 'w' перед чтением приводит к потере данных. Для чтения используется 'r', для добавления 'a', для перезаписи 'w'.

Как записать несколько строк без множественных вызовов write?

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

lines = ['Альфа', 'Бета', 'Гамма']
with open('lines.txt', 'w', encoding='utf-8') as f:
    for line in lines:
        print(line, file=f)

Пояснение: каждый вызов print добавляет символ новой строки, если не указан параметр end.

Как добавить данные в конец существующего файла?

Режим 'a' открывает файл для добавления. Если файл отсутствует, он создается.

with open('log.txt', 'a', encoding='utf-8') as f:
    print('Новая запись', file=f)
Ошибка: режим 'w' в такой задаче очищает файл. Для сохранения старых данных используется 'a'.

Как работать с бинарными файлами и изображениями?

Бинарный режим 'rb' и 'wb' возвращает и принимает bytes. Кодировка в этом режиме не применяется.

with open('image.png', 'rb') as src:
    data = src.read()
with open('copy.png', 'wb') as dst:
    dst.write(data)

Пояснение: для текстовых данных используются str, для бинарных bytes. Смешивание типов вызывает TypeError.

Как указать кодировку и обработать ошибки декодирования?

Параметр encoding задает кодировку. Параметр errors управляет реакцией на некорректные байты.

with open('text.txt', 'r', encoding='utf-8', errors='replace') as f:
    content = f.read()
print(content)
Ошибка UnicodeDecodeError возникает при чтении файла в неверной кодировке. Решение: указать encoding='utf-8', 'cp1251' или errors='replace'.

Как использовать pathlib для чтения и записи?

Path.read_text и Path.write_text делают код короче и переносимым.

from pathlib import Path

p = Path('pathlib.txt')
p.write_text('Текст через pathlib', encoding='utf-8')
content = p.read_text(encoding='utf-8')
print(content)

Пояснение: pathlib автоматически управляет открытием и закрытием файла.

Частые ошибки при работе с файлами

FileNotFoundError: файл не найден. Решение: проверить путь, создать файл или обработать исключение. PermissionError: нет прав доступа. Решение: изменить права или выбрать другой путь. IsADirectoryError: путь указывает на папку. Решение: указать файл. TypeError: запись str в бинарный файл или bytes в текстовый. Решение: согласовать режим и тип данных. Потеря данных при 'w' вместо 'a'. Решение: выбирать режим по задаче.

Расширенные примеры чтения и записи файлов в Python

Примеры показывают разные сценарии: обработка больших файлов, подсчет строк, фильтрация, временные файлы, CSV, JSON, сжатие, произвольный доступ, буферизация, кодировки, атомарная запись.

Пример 1: чтение большими блоками

Пример
def read_in_chunks(path, size=4):
    with open(path, 'r', encoding='utf-8') as f:
        while True:
            chunk = f.read(size)
            if not chunk:
                break
            yield chunk

with open('chunks.txt', 'w', encoding='utf-8') as f:
    f.write('abcdefghij')

print(list(read_in_chunks('chunks.txt', 3)))
['abc', 'def', 'ghi', 'j']

Пояснение: генератор выдает порции данных. Это полезно для потоковой обработки.

Пример 2: подсчет строк и слов в файле

Пример
with open('text.txt', 'w', encoding='utf-8') as f:
    print('один два', file=f)
    print('три четыре', file=f)
    print('пять', file=f)

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

line_count = len(lines)
word_count = sum(len(line.split()) for line in lines)
print(line_count, word_count)
3 5

Пояснение: readlines возвращает список строк. Метод split делит строку по пробельным символам.

Пример 3: фильтрация строк при записи нового файла

Пример
with open('source.txt', 'w', encoding='utf-8') as f:
    print('важное', file=f)
    print('мусор', file=f)
    print('важное тоже', file=f)

with open('source.txt', 'r', encoding='utf-8') as src:
    with open('filtered.txt', 'w', encoding='utf-8') as dst:
        for line in src:
            if 'мусор' not in line:
                dst.write(line)

with open('filtered.txt', 'r', encoding='utf-8') as f:
    print(f.read())
важное
важное тоже

Пояснение: вложенные with открывают два файла. Чтение и запись идут построчно.

Пример 4: временный файл через tempfile

Пример
import tempfile
import os

fd, path = tempfile.mkstemp(text=True)
try:
    with os.fdopen(fd, 'w', encoding='utf-8') as f:
        print('Временные данные', file=f)
    with open(path, 'r', encoding='utf-8') as f:
        print(f.read())
finally:
    os.remove(path)
Временные данные

Пояснение: mkstemp создает файл и дескриптор. fdopen превращает дескриптор в файловый объект. Удаление выполняется вручную.

Пример 5: запись CSV без внешних библиотек

Пример
rows = [
    ['имя', 'возраст'],
    ['Анна', '28'],
    ['Иван', '34'],
]

with open('people.csv', 'w', encoding='utf-8', newline='') as f:
    for row in rows:
        print(','.join(row), file=f)

with open('people.csv', 'r', encoding='utf-8', newline='') as f:
    print(f.read())
имя,возраст
Анна,28
Иван,34

Пояснение: newline='' предотвращает двойные переводы строк в CSV на некоторых платформах. Для сложных случаев есть модуль csv.

Пример 6: модуль csv для чтения и записи

Пример
import csv

with open('users.csv', 'w', encoding='utf-8', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(['login', 'email'])
    writer.writerow(['admin', 'admin@example.com'])

with open('users.csv', 'r', encoding='utf-8', newline='') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)
['login', 'email']
['admin', 'admin@example.com']

Пояснение: csv.writer и csv.reader корректно обрабатывают кавычки и разделители.

Пример 7: атомарная запись через временный файл и замену

Пример
import os
import tempfile

target = 'config.txt'
with tempfile.NamedTemporaryFile('w', encoding='utf-8', delete=False, dir='.') as tmp:
    print('ключ=значение', file=tmp)
    temp_name = tmp.name

os.replace(temp_name, target)

with open(target, 'r', encoding='utf-8') as f:
    print(f.read())
ключ=значение

Пояснение: os.replace атомарно заменяет целевой файл. Такой прием снижает риск частично записанного файла.

Пример 8: произвольный доступ через seek и tell

Пример
with open('seek.txt', 'w+', encoding='utf-8') as f:
    f.write('0123456789')
    f.seek(3)
    part = f.read(4)
    pos = f.tell()
print(part, pos)
3456 7

Пояснение: seek перемещает позицию. tell возвращает текущую позицию. В текстовом режиме смещения зависят от кодировки, поэтому для точного доступа лучше бинарный режим.

Пример 9: бинарное копирование с буфером

Пример
buffer_size = 1024
with open('input.bin', 'wb') as f:
    f.write(b'0123456789' * 200)

with open('input.bin', 'rb') as src, open('output.bin', 'wb') as dst:
    while True:
        chunk = src.read(buffer_size)
        if not chunk:
            break
        dst.write(chunk)

print(open('output.bin', 'rb').read()[:10])
b'0123456789'

Пояснение: чтение блоками снижает расход памяти. Оба файла открыты в бинарном режиме.

Пример 10: обработка исключений при чтении

Пример
try:
    with open('missing.txt', 'r', encoding='utf-8') as f:
        data = f.read()
except FileNotFoundError:
    print('Файл отсутствует')
except PermissionError:
    print('Нет доступа')
except UnicodeDecodeError:
    print('Проблема с кодировкой')
else:
    print(data)
Файл отсутствует

Пояснение: разные исключения обрабатываются отдельно. Это дает понятные сообщения.

Пример 11: запись и чтение JSON

Пример
import json

data = {'name': 'Анна', 'age': 28}
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

with open('data.json', 'r', encoding='utf-8') as f:
    loaded = json.load(f)
print(loaded['name'], loaded['age'])
Анна 28

Пояснение: ensure_ascii=False сохраняет русские символы. indent=2 делает файл читаемым.

Пример 12: сжатый файл gzip

Пример
import gzip

with gzip.open('text.gz', 'wt', encoding='utf-8') as f:
    print('Сжатая строка', file=f)

with gzip.open('text.gz', 'rt', encoding='utf-8') as f:
    print(f.read())
Сжатая строка

Пояснение: gzip.open поддерживает текстовые режимы 'wt' и 'rt'. Для бинарных данных используются 'wb' и 'rb'.

Пример 13: чтение файла с обратным порядком строк

Пример
with open('reverse.txt', 'w', encoding='utf-8') as f:
    print('первая', file=f)
    print('вторая', file=f)
    print('третья', file=f)

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

for line in reversed(lines):
    print(line.rstrip())
третья
вторая
первая

Пояснение: readlines загружает все строки в память. Для больших файлов применяется отдельный алгоритм с seek.

Пример 14: проверка существования и размера файла

Пример
import os

path = 'check.txt'
with open(path, 'w', encoding='utf-8') as f:
    f.write('проверка')

print(os.path.exists(path))
print(os.path.getsize(path))
True
6

Пояснение: os.path.exists проверяет наличие. os.path.getsize возвращает размер в байтах. Для русских букв в UTF-8 размер может отличаться от числа символов.

Чтение и запись файлов в Python - comments

En
чтение запись файлов python (python)