Практические задания по файловому вводу-выводу в Python для опытных разработчиков
Задания на работу с файлами в Python: продвинутые примеры
Рассмотрим типовое задание: чтение файла логов access.log, отбор строк с кодами ошибок 5xx и запись в errors.log. Ниже представлены различные подходы с оценкой эффективности и типичных проблем.
Наиболее эффективное решение: контекстный менеджер + построчное чтение
with open('access.log', 'r', encoding='utf-8') as infile, \
open('errors.log', 'w', encoding='utf-8') as outfile:
for line in infile:
if ' 5' in line:
outfile.write(line)ввод программ на python (ввод данных в программе python)
Пояснение: менеджер контекста гарантирует закрытие файлов даже при возникновении ошибок. Построчное чтение не загружает весь файл в память, что оптимально для больших логов. Проверка ' 5' in line работает для типового формата, когда код ошибки находится после пробела (например, строка содержит ' 500 ').
Типичные ошибки и способы их решения
- Забыли указать параметр encoding - может вызвать UnicodeDecodeError для файлов с не-ASCII символами. Решение: всегда указывать явно кодировку.
- Проверка ' 5' может захватить ложные совпадения, например, ' 50000' или ' 5000'. Решение: использовать регулярное выражение для точного поиска кода ошибки (например, pattern = r'\s5\d{2}\s').
- Строки могут содержать символы перевода строки с разными окончаниями (\r\n, \n). При записи line уже содержит перевод, поэтому дополнительный \n не требуется.
- Ошибка FileNotFoundError, если файл не существует. Решение: обернуть код в try-except или проверять существование через Path.exists().
Вариант 1: Чтение всего файла в память
Как прочитать файл целиком и обработать все строки в памяти?
with open('access.log', 'r', encoding='utf-8') as f:
lines = f.readlines()
with open('errors.log', 'w', encoding='utf-8') as f:
for line in lines:
if ' 5' in line:
f.write(line)Python file io (ввод-вывод файлов в python)
Этот метод прост для понимания, но потребляет много памяти, так как все строки загружаются в список. Подходит для файлов размером до нескольких сотен мегабайт. Если файл огромен, программа может упасть с MemoryError.
Типичные ошибки: при работе с большими файлами - переполнение памяти. Решение: заменить на построчное чтение из варианта rbase.
Вариант 2: Функциональный стиль с filter()
Как использовать встроенную функцию filter() для фильтрации строк?
def is_error(line):
return ' 5' in line
with open('access.log', 'r', encoding='utf-8') as infile, \
open('errors.log', 'w', encoding='utf-8') as outfile:
outfile.writelines(filter(is_error, infile))
Python temp files (временные файлы в python)
Функция filter() возвращает итератор, поэтому файл читается лениво. Код получается лаконичным, но может быть сложнее для отладки. Такой подход хорошо сочетается с другими функциями высшего порядка.
Проблемы: filter() не принимает дополнительные аргументы для функции, поэтому приходится определять отдельную функцию. Ошибка: если файл не открывается корректно - то же, что и в rbase.
Вариант 3: Использование pathlib
Как применить современный модуль pathlib для чтения и записи?
from pathlib import Path
in_path = Path('access.log')
out_path = Path('errors.log')
text = in_path.read_text(encoding='utf-8')
lines = text.splitlines(keepends=True)
errors = [line for line in lines if ' 5' in line]
out_path.write_text(''.join(errors), encoding='utf-8')Методы read_text() и write_text() крайне удобны для небольших файлов. Недостаток - полная загрузка файла в память и создание промежуточных списков. Для большого файла лучше использовать построчные методы.
Ошибка: splitlines() по умолчанию удаляет символы перевода строки. Используйте keepends=True, чтобы сохранить их. Иначе строки сольются при записи.
Расширенные примеры работы с файлами в Python
Пример 1: Использование mmap для быстрого поиска в большом файле
Для очень больших файлов может потребоваться низкоуровневый доступ к памяти. Модуль mmap отображает файл в виртуальную память, позволяя работать с ним как с байтовым массивом.
import mmap
with open('access.log', 'r+b') as f:
mm = mmap.mmap(f.fileno(), 0)
offset = 0
errors = []
while True:
pos = mm.find(b' 5', offset)
if pos == -1:
break
end = mm.find(b'\n', pos)
if end == -1:
end = len(mm)
line = mm[pos:end].decode('utf-8')
errors.append(line)
offset = end + 1
mm.close()
with open('errors_mmap.log', 'w', encoding='utf-8') as f:
f.writelines(errors)Результат: файл errors_mmap.log содержит строки логов с кодами 5xx. Время выполнения для файла размером 2 ГБ сокращается по сравнению с построчным чтением благодаря прямому доступу к памяти.
Важно: mmap.mmap() требует режим открытия файла 'r+b' (чтение+запись в бинарном режиме). Для чистого чтения можно использовать os.open().
Пример 2: Работа с CSV и DictWriter
Когда данные структурированы (например, таблица логов), удобно применять модуль csv.
import csv
with open('data.csv', 'r', newline='', encoding='utf-8') as infile:
reader = csv.DictReader(infile)
rows = [row for row in reader if int(row['status']) >= 500]
with open('errors.csv', 'w', newline='', encoding='utf-8') as outfile:
fieldnames = reader.fieldnames
writer = csv.DictWriter(outfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(rows)Результат: файл errors.csv содержит только строки со статусом >=500, сохранённые в том же CSV-формате с заголовками.
Пример 3: Временный файл с помощью tempfile
Для промежуточных результатов или тестирования удобно создавать временные файлы, которые автоматически удаляются.
import tempfile
import os
with tempfile.NamedTemporaryFile(mode='w+', suffix='.log', delete=True) as tmp:
tmp.write('temp data\n')
tmp.flush()
# Используем путь к временному файлу
print('Temp file path:', tmp.name)
# Файл будет удалён при выходе из контекстаВывод: Temp file path: /tmp/tmpabc123.log После завершения блока файл удаляется.
Пример 4: Копирование бинарного файла с shutil.copyfileobj
Для копирования больших бинарных данных (изображения, архивы) эффективно использовать буферизированное копирование.
import shutil
with open('image.jpg', 'rb') as src, open('copy.jpg', 'wb') as dst:
shutil.copyfileobj(src, dst, length=1024*1024) # 1 МБ буферРезультат: создаётся точная копия файла image.jpg под именем copy.jpg.
Пример 5: Эмуляция файла с помощью io.StringIO
Для модульного тестирования или работы со строками как с файлами применяется StringIO из модуля io.
from io import StringIO
buffer = StringIO()
buffer.write('line1\nline2\n')
buffer.seek(0)
for line in buffer:
print(line.strip())Вывод: line1 line2
Применение: удобно для передачи строкового содержимого в функции, ожидающие файловый объект.