Функции для работы с файлами — 4.2, Информатика 7 класс, Кадыркулов: разбор и ответы
Ookul.kz · разбор уроков
Қазақша

Разберём любой номер вместе!

4.2. Функции для работы с файлами

Информатика, 7 класс. Учебник: Кадыркулов Р. А., Рыскулбекова А. Д., Нурмуханбетова Г. К. (Алматыкітап баспасы, 2023). Раздел 4: Программирование алгоритмов на языке Python. Страницы 111–114.

Чему научишься

  • Читать файл по строкам функцией readline(), целиком или первые n символов.
  • Ставить «курсор» в нужное место файла функцией seek(n).
  • Читать ровно n символов методом read(n).
  • Заменять часть данных в файле, записав новые символы с нужной позиции.
  • Решать задачи, где числа в файле надо «вырезать» по позициям.

Разминка

  • Какие функции и методы для работы с файлами ты уже знаешь? open(), read(), write(), close(). А ещё split(), чтобы разрезать прочитанную строку.
  • На что обращать особое внимание при записи в файл и чтении из файла? Выбрать правильный режим ('r', 'w', 'a'), помнить, что read() и write() работают со строками, и обязательно закрывать файл.

Разбираемся

Двоичные файлы: просто запомни

В прошлый раз мы работали с текстовыми файлами. Для двоичных (картинки, музыка) к режиму добавляют букву 'b': например, чтобы читать двоичный файл, пишут 'rb' вместо 'r'. Пока мы работаем только с текстом, а двоичными файлами займёшься в старших классах.

readline(): читаем по строке

У файла есть строки: каждая заканчивается переводом строки \n. Функция readline() читает одну строку.

  • Без параметра readline() читает строку целиком, до \n включительно.
  • С параметром readline(n) читает только первые n символов строки.

Возьмём файл input.txt из двух строк (числа и буквы здесь мои):

qwertyuiopasdfgh
9876543210

Хотим первые 6 букв первой строки и первые 3 цифры второй.

fin = open("input.txt", "r")
p = fin.readline(6)      # первые 6 символов первой строки: 'qwerty'
rest = fin.readline()    # остаток первой строки: 'uiopasdfgh\n'
h = fin.readline(3)      # первые 3 символа второй строки: '987'
fin.close()

Зачем нужен «пустой» readline() посередине? Чтобы перескочить остаток первой строки. Иначе следующий readline(3) продолжил бы с буквы u, а не с цифр.

💡 Курсор в файле как палец на строчке в книге: прочитал кусок, палец сдвинулся вперёд.

seek(): поставь курсор куда нужно

Обычно read() идёт по файлу от начала до конца. Функция seek(n) позволяет переставить курсор в позицию n и читать (или писать) оттуда. Позиции считаются с нуля: первый символ это позиция 0.

Возьмём файл 0123456789.

f = open("input.txt", "r")
f.seek(4)
print(f.read(3))      # 456  (читаем 3 символа с позиции 4)
print(f.read(3))      # 789  (курсор продолжил с места остановки)
f.seek(0)             # вернули курсор в начало
print(f.read())       # 0123456789  (без параметра: всё до конца)
print(f.read())       # пусто: курсор уже в конце
f.close()

⚠️ Частая ошибка. Считать позиции с единицы. Символ 0123456789 с номером 4 это цифра 4, потому что нумерация идёт с нуля.

⚠️ Частая ошибка. Забыть, что курсор двигается сам после каждого чтения. Второй read(3) продолжит с того места, где закончился первый. Чтобы начать заново, нужен seek(0).

Заменяем кусок файла

Если поставить курсор в середину и записать новые символы, они затрут старые на тех же местах. Остальное не меняется. Пример: в файле алфавит abcdefghijklmnopqrstuvwxyz, хотим заменить пять букв, начиная с позиции 5, значком #.

f = open("input.txt", "w")
f.write("abcdefghijklmnopqrstuvwxyz")   # записали алфавит
f.seek(5)                               # курсор на позицию 5: буква f
f.write("#####")                        # затёрли пять букв: f g h i j
f.close()

Файл станет таким: abcde#####klmnopqrstuvwxyz.

⚠️ Частая ошибка. В этих примерах файл содержит только латинские буквы и цифры, где один символ занимает одну позицию. С русским текстом в кодировке UTF-8 позиции seek() считаются иначе, поэтому для упражнений урока берём латиницу и цифры.

📌 Схема для чисел, записанных в файле «как попало»: seek(позиция) (встать) → read(длина) (взять столько символов) → int(...) (превратить в число).

👨‍👩‍👧 Родителю. Закладка в книге прекрасно объясняет курсор. Спросите ребёнка: «Куда встанет закладка после того, как ты прочитал абзац? А если я попрошу открыть страницу 50?» Это read() и seek() на пальцах.

Проверь себя

  • Чем readline() без параметра отличается от readline(5)? Без параметра читается вся строка до перевода строки. С параметром 5 читаются первые пять символов.
  • Что делает seek(n)? Переставляет курсор в файле на позицию n: дальше чтение или запись идёт оттуда.
  • Как прочитать ровно 4 символа начиная с позиции 7? f.seek(7), затем f.read(4).
  • Что будет, если после seek() не читать, а записать? Новые символы затрут старые на этих позициях.
  • Зачем в примере с буквами и цифрами понадобился «пустой» readline() между двумя чтениями? Чтобы пропустить остаток первой строки и перейти ко второй.

Решаем упражнения

Практическая работа

№ 1 · «Практическая работа», задание 1

Файл Input.txt содержит трёх-, четырёх- и пятизначное числа через пробел: 256 4584 69581. Посчитай их сумму и запиши в Output.txt. Должно получиться 74421.

Как думать. Числа записаны подряд, длины известны: 3, 4, 5 цифр. Значит, можно вырезать каждое по позиции. Позиции считаем с нуля: 256 с позиции 0, пробел на 3, 4584 с позиции 4, пробел на 8, 69581 с позиции 9.

Как сделать. Шаги: открыть оба файла; прочитать три числа по позициям; превратить в числа через int(); записать сумму как строку; закрыть оба файла. Входной файл создай в Блокноте или программой: в него просто надо записать 256 4584 69581.

fin = open("Input.txt", "r")
fout = open("Output.txt", "w")
a = int(fin.read(3))      # трёхзначное с позиции 0
fin.seek(4)
b = int(fin.read(4))      # четырёхзначное с позиции 4
fin.seek(9)
c = int(fin.read(5))      # пятизначное с позиции 9
fout.write(str(a + b + c))
fin.close()
fout.close()

Запуск: в Output.txt лежит 74421.

💡 Есть и проще: numbers = map(int, fin.read().split()), а потом sum(numbers). Он режет по пробелам и не зависит от позиций. Но урок про seek(), поэтому учимся вырезать. Я проверил оба варианта: оба дают 74421.

Ответ: 74421.

Задание

№ 2 · «Задание», задача 1

Базовый уровень. В файле строка ajsjsidmmkkkddmdmd. Что получится после серий команд: а) seek(3), read(5); б) seek(5), read(); в) seek(0), read(1)?

Как думать. Выпиши буквы с номерами: a0 j1 s2 j3 s4 i5 d6 m7 m8 k9 k10 k11 d12 d13 m14 d15 m16 d17.

Решение.

а) seek(3): курсор на позиции 3 (буква j). read(5) берёт пять символов: j, s, i, d, m, то есть jsidm.

б) seek(5): курсор на i. read() читает до конца: idmmkkkddmdmd.

в) seek(0): в начало. read(1) читает один символ: a.

Я проверил запуском: 'jsidm', 'idmmkkkddmdmd', 'a'.

Ответ: а) jsidm; б) idmmkkkddmdmd; в) a.

№ 3 · «Задание», задача 2

Средней сложности. В файле строка 65 859 365. Какие команды нужны, чтобы выделить из неё числа 59 и 65?

Как думать. Пронумеруй символы: 6(0) 5(1) пробел(2) 8(3) 5(4) 9(5) пробел(6) 3(7) 6(8) 5(9). Нужное число занимает две позиции подряд.

Решение.

  • Число 59 стоит в середине второго числа, цифры на позициях 4 и 5. Команды: seek(4) и read(2), получим 59.
  • Число 65 стоит в самом начале: seek(0) и read(2), получим 65. Но 65 есть ещё и в конце строки (позиции 8 и 9): seek(8) и read(2) дадут тоже 65.
f = open("s.txt", "r")
f.seek(4)
print(f.read(2))      # 59
f.seek(0)
print(f.read(2))      # 65
f.seek(8)
print(f.read(2))      # 65 (из конца строки)
f.close()

Ответ: для 59: seek(4), read(2); для 65: seek(0), read(2) (или seek(8), read(2)).

№ 4 · «Задание», задача 3

Средней сложности. В Input.txt целые числа a, b, c, d и p через пробел. Найди сумму a и b, разность c и d. Каждое из этих двух чисел раздели на p, а остатки перемножь. Результат запиши в Output.txt. Пример: 25 18 45 12 9 даёт 42.

Как думать. Остаток от деления это %. Значит, нужно ((a + b) % p) * ((c - d) % p). Скобки важны: без них порядок действий другой.

Решение.

fin = open("Input.txt", "r")
a, b, c, d, p = map(int, fin.read().split())   # пять чисел сразу
fin.close()

r1 = (a + b) % p          # остаток от деления суммы на p
r2 = (c - d) % p          # остаток от деления разности на p

fout = open("Output.txt", "w")
fout.write(str(r1 * r2))
fout.close()

Запуск на 25 18 45 12 9: в файле 42.

Ответ: ((a + b) % p) * ((c - d) % p); для примера 42.

№ 5 · «Задание», задача 4

⭐ повышенной сложности. В sum.txt четыре действительных двузначных числа с сотыми долями: 12.74 15.68 98.18 32.84. Округли их до целых, найди сумму, запиши в Result.txt.

Как думать. Числа превращаем в вещественные через float(). Округляет функция round(). Но порядок действий важен: можно сначала округлить каждое, а потом сложить, а можно сначала сложить, а потом округлить.

Решение. Как сказано в условии, сначала округляем каждое число: 13, 16, 98, 33. Сумма 13 + 16 + 98 + 33 = 160.

fin = open("sum.txt", "r")
nums = map(float, fin.read().split())     # четыре вещественных числа
fin.close()

total = 0
for x in nums:
    total += round(x)      # округлили каждое, потом прибавили

fout = open("Result.txt", "w")
fout.write(str(total))
fout.close()

Запуск: в Result.txt будет 160.

📕 В учебнике для этих данных ответ 159. Но если следовать условию («округлите числа и вычислите их сумму»), получается 160. А 159 выходит, если сначала сложить числа (159,44), а потом округлить итог: round(sum(nums)). Решай по тексту условия: сначала округлить каждое. Если учитель ждёт 159, используй второй вариант.

⚠️ Частая ошибка. round() в Питоне округляет «до чётного» ровно посередине: round(2.5) даёт 2, а round(3.5) даёт 4. В этих данных таких чисел нет, но запомни.

Ответ: 160 (округляем каждое число, как сказано в условии). Если сначала сложить: 159.

№ 6 · «Задание», задача 5

⭐ повышенной сложности. Во входном файле a.txt записано математическое выражение, например 1456+78544. Составь программу, которая вычислит его значение и выведет на экран. Для примера должно быть 80000.

Как думать. Из файла приходит строка '1456+78544'. Питон умеет вычислять выражение, записанное строкой, функцией eval(). Другой путь: разрезать строку по знаку + и сложить части.

Решение.

Вариант 1, самый короткий:

fin = open("a.txt", "r")
expr = fin.read().strip()      # strip() убирает лишние пробелы и перевод строки
fin.close()
print(eval(expr))              # eval вычисляет выражение из строки

Вариант 2, если в файле только сложение:

fin = open("a.txt", "r")
expr = fin.read().strip()
fin.close()
x, y = expr.split("+")         # '1456' и '78544'
print(int(x) + int(y))

Оба варианта я запускал: выводят 80000. С eval ещё посчитается и 300*12-1600: получится 2000.

⚠️ Частая ошибка. eval() выполняет любой текст как код Питона. Использовать его можно только для своих файлов, а чужим данным доверять нельзя.

Ответ: 80000. Программа: print(eval(expr)), где expr прочитано из файла.

Домашнее задание

№ 7 · «Домашнее задание»

«Письмо другу». Напиши другу письмо о том, как прочитать данные из файла. Расскажи про особенности чтения из файла и его значение в программировании, с какими трудностями ты столкнулся и какие новые возможности в программировании открывает эта тема.

Как думать. Письмо живое, как сообщение другу. План: что узнал, как это делается, где было сложно, что теперь умеешь.

Пример ответа.

Привет, Арман!

Сегодня на информатике я узнал, как программа читает данные из файла. Теперь мне не нужно каждый раз вводить числа с клавиатуры. Я записываю их в текстовый файл, а программа сама их открывает: open("input.txt", "r"), потом read(), а потом обязательно close().

Ещё есть классная штука seek(). Это курсор: ставишь его на нужную позицию и читаешь только то, что надо, например read(4). Сначала я путался, что позиции считаются с нуля. Из-за этого сдвигался на один символ. А ещё из файла всё приходит строкой, и для чисел нужен int().

Теперь можно делать справочники, записи результатов и даже читать выражение из файла и считать его. Попробуй сам! Начни с файла из двух чисел.

Пока! Айдар

Ответ: свободное письмо; в нём стоит упомянуть open, read/readline, seek, close, нумерацию с нуля и перевод строки в число.

Шпаргалка

Термины: параметр функции, readline(), seek(), курсор, позиция, режим 'b'.

Мини-тест

← 4.1. Работа с файлами · 4.3–4.4. Программирование алгоритмов ветвления →