Занятие № 9. Применение файлов для решения задач

Цель: научится использовать файлы для чтения и записи информации.

Теория

Чтение файла

Файлы можно разбить на два вида:

  • Plaintext (текстовые) файлы – содержат информацию, которая понятна человеку;

  • Бинарные файлы – файлы, открыв которые в текстовом редакторе, человек не сможет понять содержимого (исполняемые файлы, изображения, документы и др.).

В заданиях будем использовать только текстовые файлы.

Чтобы открыть файл используется функция open(<путь>, <режим доступа>). Эта функция возвращает файловый объект, который будет связан с файлом в файловой системе. Аргумент <путь> - это строка с расположением файла, <режим доступа> - строка с режимом в котором мы открываем файл: чтение "r" или запись "w". В следующем коде переменная file_obj будет содержать ссылку на файл с именем x ? , открытый для x чтения:

script.py
# параметр encoding указывает на кодировку открываемого файла
file_obj = open("verse.txt", "r", encoding="utf-8")

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

В такой форме записи пути, файл verse.txt должен находиться в той же папке, что и Python-скрипт. Папка из которой запускается скрипт считается для него текущим рабочим каталогом.

graph TD
    folder["<i class="fa-solid fa-folder-open"></i> Скрипты<br>(текущий рабочий каталог)"]
    script([<i class="fa-regular fa-file-code"></i> script.py])
    file(["<i class="fa-regular fa-file-lines"></i> verse.txt"])

    folder-->script
    folder-->file
Рисунок 1

После использования, файл нужно закрыть методом close():

file_obj.close()

Если этого не сделать, операционная система будет считать, что файл ещё занят и не даст открыть его другим программам.

Для чтения содержимого текстового файла используются следующие методы файлового объекта:

Методы чтения содержимого файла
Метод Назначение
<файл>.read() Возвращает всё содержимое файла в одной строке (str).
<файл>.readline() Читает следующую строку файла и возвращает её (str).
<файл>.readlines() Возвращает список (list) строк файла.

Используем все три метода для чтения содержимого следующего файла:

verse.txt
У лукоморья дуб зелёный;
Златая цепь на дубе том:
И днём и ночью кот учёный
Всё ходит по цепи кругом;
Идёт направо — песнь заводит,
Налево — сказку говорит.

Прочитаем всё содержимое файла в виде одной строки:

file_obj = open("verse.txt", "r")
text = file_obj.read() # чтение файла целиком
print(text)
file_obj.close()

      
file_obj = open("verse.txt", "r")
text = file_obj.read() # чтение файла целиком
print(text)
file_obj.close()

Прочитаем файл построчно:

file_obj = open("verse.txt", "r")

line = file_obj.readline() # читаем первую строку
print(line)
line = file_obj.readline() # читаем вторую строку
print(line)

file_obj.close()

      
file_obj = open("verse.txt", "r")

line = file_obj.readline() # читаем первую строку
print(line)
line = file_obj.readline() # читаем вторую строку
print(line)

file_obj.close()

Обратите внимание, после каждой строки появилась пустая строка. В файле, чтобы обозначить конец строки ставится управляющая последовательность \n - перенос строки. Реально в переменной line хранится строка У лукоморья дуб зелёный;\n. Функция print() не выводит управляющие символы а интерпретирует их значение.

Запишем все строки в список:

file_obj = open("verse.txt", "r")

lines_list = file_obj.readlines() # список строк
print(lines_list[0:2]) # выведем первые два элемента списка

file_obj.close()

      
file_obj = open("verse.txt", "r")

lines_list = file_obj.readlines() # список строк
print(lines_list[0:2]) # выведем первые два элемента списка

file_obj.close()

Запись в файл

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

Предположим, что нам нужно записать в файл sq_numbers.txt квадраты целых чисел от 1 до 12. Откроем файл для записи:

output = open("sq_numbers.txt", "w")

Далее запускаем цикл for, чтобы перебрать числа из заданного отрезка:

for number in range(1, 13):
    square = number * number

Осталось записать число square в файл: output.write(square). Но на этой инструкции появится ошибка - записать в файл можно только данные типа str. Необходимо преобразовать значение в строку:

for number in range(1, 13):
    square = number * number
    output.write(str(square))

После запуска скрипта мы увидим в файле такой текст:

149162536496481100121144

Метод write() не добавляет перенос на новую строку. Нужно самостоятельно добавить управляющий символ \n к записываемой строке:

output.write(str(square) + "\n")

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

Режим "a" позволяет открыть файл для дозаписи в конец файла.

Относительный и абсолютный путь к файлу

Рисунок 2 показывает пример структуры каталогов и файлов.

Если мы хотим открыть файл temp.txt в скрипте work.py, мы напрямую напишем имя файла в функции: open("temp.txt", "r").

Как открыть в этом же скрипте файл data.txt, который находятся в другой папке? Можно использовать абсолютный путь в котором указывается полная последовательность папок от корневого каталога. В нашем примере: C:\Проекты\Данные\data.txt. Второй вариант - использовать относительный путь: ..\Проекты\Данные\data.txt. Символы ..\ означают, что мы поднимаемся на один уровень выше, относительно текущего рабочего каталога. Чтобы в скрипте work.py открыть файл val.csv запишем следующий относительный путь: ..\..\val.csv.

graph TD
    folderC["<i class="fa-solid fa-folder-open"></i> C:\"]
    scriptCSV([<i class="fa-solid fa-file-csv"></i> val.csv])
    file1(["<i class="fa-regular fa-file-lines"></i> exp.txt"])
    file2(["<i class="fa-regular fa-file-lines"></i> data.txt"])
    script3(["<i class="fa-regular fa-file-lines"></i> temp.txt"])
    foto(["<i class="fa-regular fa-image"></i> cat.jpg"])

    scriptsF["<i class="fa-solid fa-folder-open"></i> Скрипты<br>(<strong>текущий рабочий каталог</strong>)"]
    dataF["<i class="fa-solid fa-folder-open"></i> Данные"]
    projF["<i class="fa-solid fa-folder-open"></i> Проекты"]
    
    script2([<i class="fa-regular fa-file-code"></i> work.py])

    folderC---scriptCSV
    projF---scriptsF
    folderC---projF
    projF---dataF

    scriptsF---script2
    scriptsF---script3

    dataF---file1
    dataF---file2
    dataF---foto
Рисунок 2
±

Вам нужно открыть для чтения файл оценки.csv в скрипте stats.py. Скрипт запускается из папки задача. На рисунке показана файловая структура:

graph TD
    folder["<i class="fa-solid fa-folder-open"></i> D:\"]
    csv([<i class="fa-solid fa-file-csv"></i> оценки.csv])
    script(["<i class="fa-regular fa-file-lines"></i> stats.py"])
    folder_task["<i class="fa-solid fa-folder-open"></i> задача"]
    folder_proj["<i class="fa-solid fa-folder-open"></i> проект"]

    folder---folder_task
    folder_task---script
    folder---folder_proj
    folder_proj---csv
Рисунок 3

Выберите варианты функции open() подходящие для решения задачи.


Безопасное открытие файла

С помощью инструкции with можно автоматически закрывать файл после использования:

with <файловый объект> as <имя>:
    <блок инструкций>

Запишем решение задачи с записью квадратов чисел с помощью инструкции with:

with open("sq_numbers.txt", "w") as output:
    for number in range(1, 13):
        square = number * number
        output.write(str(square) + "\n")

После выполнения инструкций внутри with, файл output будет закрыт автоматически.

Примеры

Перед началом работы скачайте архив по этой ссылке. В архиве находятся все файлы, которые используются в примерах и заданиях.

Распакуйте архив на рабочем диске и сохраняйте скрипты рядом с распакованными файлами.

Пример № 1 (ex01.py)

Напишите программу, которая расчитает, сколько времени понадобится на прочтение текста. Средняя скорость чтения 1200 символов в минуту. Текст хранится в файле под именем Шерлок_Холмс.txt.

Открываем файл для чтения

Чтобы открыть файл используется функция x open(). Первым аргументом функция принимает путь к файлу. А вторым - режим доступа. При чтении содержимого файла второй аргумент должен иметь значение x r. Прочитаем всё содержимое файла с помощью метода x read().


Запишите следующий код, чтобы открыть файл для чтения и вывести на экран первые 255 символов текста:

book = open("Шерлок_Холмс.txt", 'r', encoding="utf-8")
book_text = book.read()
print(book_text[:255])
book.close()

Сохраните скрипт под именем ex01.py. Программу нужно сохранить в ту же папку что и текстовый документ.

Расчёт времени чтения

Для выполнения расчётов опишем функцию read_time(text, speed), где параметр text - строка, speed - скорость чтения. Функция рассчитает время чтения путём деления количества символов в тексте на скорость чтения. Деление сделаем целочисленным, чтобы количество минут получилось целым числом. В Python целочисленное деление записывается с помощью оператора x //.


Добавьте к существующему решению следующий код:

def read_time(text, speed):
    symb_num = len(text)
    return symb_num // speed

time = read_time(book_text, 1200)
print(time)

Запустите программу. На экран выведется количество минут необходимое для чтения текста.

Вывод ответа

Переведём время чтения из минут в часы. Для этого целочисленно поделим всё время на 60. В остатке получим количество минут, которое также нужно добавить к ответу. В Python деление с остатком записывается с помощью оператора x %.


Добавьте к существующему решению следующий код:

hours = time // 60  # количество часов 
minutes = time % 60 # оставшиеся минуты
print(f"Время чтения: {hours} ч, {minutes} мин")

Запустите программу.

Задача решена.

Пример № 2 (ex02.py)

Запишите в файл под именем таблица.csv таблицу значений функции \(y=\frac{5}{x}\), для x от 5 до 10 с шагом 0.2. Значения запишите с точностью до трёх знаков после запятой.

# открываем файл для чтения
table_file = open("table.csv", 'w', encoding="utf8")

x = 5.0
while x <= 10:
    y = 5 / x
    table_file.write(f"{x:.3f};{y:.3f} \n")
    x += 0.2

table_file.close()

Чтобы отформатировать вывод вещественных чисел используем такой синтаксис:

Указание формата данных в f-строке

Указание формата данных в f-строке

Откройте получившийся файл в табличном процессоре (Office Excel, LibreCalc). Первые несколько строк должны выглядеть следующим образом:

Файл table.csv

Файл table.csv

Пример № 3 (ex03.py)

В файле температура.txt хранятся данные о среднегодовой температуре в Минске с 1912 по 2020 годы. Откройте файл и выведите среднегодовую температуру для представленного диапазона в файл с именем температура_формат.txt в следующем формате:

Файл temp_format.txt

Файл temp_format.txt
temp = open("temp.txt", 'r', encoding="utf-8") # открывае файл для чтения
lines = temp.readlines() # сохраняем список строк
temp.close() # закрываем файл

with open("temp_format.txt", 'w', encoding="utf-8") as out:
    year = 1912 # счётчик лет
    for line in lines:
        text = f"{year}: {float(line)} град. Цельсия\n"
        out.write(text) # запись очередной строки в файл
        year += 1

Задания для самостоятельной работы

Задание № 1 (sam01.py)

Создайте программу, которая сохранит список дел. Пользователь вводит три строки, которые сохраняются в файл заметки.txt. После ввода строк, программа читает содержимое файла и выводит его на экран.

Пример работы программы:

Введите задачу: <{Почитать книгу}> ++enter++
Введите задачу: <{Сделать домашнее задание}> ++enter++
Введите задачу: <{Погулять на свежем воздухе}> ++enter++
Список дел:
Почитать книгу
Сделать домашнее задание
Погулять на свежем воздухе

Составьте решение задачи из предложенных инструкций:

f = open('заметки.txt', 'w', encoding='utf-8')
for i in range(3):
    zametka = input("Введите текст")
    f.write(zametka + '\n')
f.close()
print('Список дел:')
f = open('заметки.txt', 'r', encoding='utf-8')
for line in f.readlines():
    print(line)
f.close()
f.close()
zametka = input("Введите текст")
f.close()
f.write(zametka + '&#92;n')
print(line)
f = open('заметки.txt', 'w', encoding='utf-8')
for i in range(3):
print('Список дел:')
f = open('заметки.txt', 'r', encoding='utf-8')
for line in f.readlines():

Задание № 2 (sam02.py)

Напишите программу с помощью которой можно приблизительно оценить, сколько минут в среднем понадобится для набора текста программы из первого примера - ex01.py. Средняя скорость набора - 190 символов в минуту.

Свою скорость набора можете проверить на этом сайте.

Задание № 3 (sam03.py)

В эксперименте измерялась зависимость силы тока, проходящей через резистор в зависимости от напряжения. Сопротивление резистора - 100 Ом. Значения напряжения менялись от 0 до 5 В с шагом 0.5 В. В файле резистор.txt с новой строки записаны измеренные значения силы тока в мА. Выведите результаты эксперимента на экран в два столбца - Напряжение (В), Сила тока (A):

Напряжение (В)    Сила тока (A)
0.0               0.00004
0.5               0.00492
1.0               0.01015
1.5               0.01488
2.0               0.02011
2.5               0.02495
3.0               0.03008
3.5               0.03487
4.0               0.04013
4.5               0.04491
5.0               0.05005

Интерактивную симуляцию эксперимента можно увидеть по следующей ссылке.

Задание № 4 (sam04.py)

Ваш друг веб-дизайнер создал для вас шаблон персональной веб-страницы. Файл с шаблоном - index.html. В тексте веб-страницы остались значения, которые нужно заменить на ваши данные:

  • %NAME% - имя и фамилия;

  • %EDU% - образование, место учёбы;

  • %DESC% - короткое описание.

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

Пример работы программы (вводите свои данные):

Имя > <{Павел}> ++enter++
Образование > <{БГПУ}> ++enter++
Описание > <{Учусь новому сам и делюсь знаниями с другими.}> ++enter++

После выполнения программы откройте файл about.html в браузере. Вы должны увидеть страницу, которая выглядит приблизительно так:

Веб-страница, заполненная данными из программы.

Веб-страница, заполненная данными из программы.

Задание № 5 (sam05.py)

В трёх разных текстовых файлах 01.txt, 02.txt и 03.txt хранятся части отчёта по лабораторной работе. Объедините текст из всех трёх файлов в один с именем отчёт.txt. В итоговом файле добавьте между частями отчётов разделитель: ##########.

После объединения файлов выведите общее количество строк в отчёте.