Занятие № 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()

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

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

Таблица 1: Методы чтения содержимого файла
Метод Назначение
<файл>.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
    folder["<i class="fa-solid fa-folder-open"></i> C:\"]
    script([<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])

    folder---script
    projF---scriptsF
    folder---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)

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

Скачайте файл сообщение.txt и сохраните его в папке с примером.

Как сохранить файл?

Чтобы сохранить этот файл, щёлкните по ссылке правой кнопкой мыши, и выберите пункт меню Сохранить объект как….

# открываем файл для чтения
file = open('сообщение.txt', 'r', encoding="utf8")

# построчно считываем файл
for line in file:
    # выводим строку на экран
    print(line, end="")

# закрываем файл
file.close()

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

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

file_name = "table.txt" # имя файла

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

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

table_file.close()
Символ переноса строки

Обратите внимание, что в f-строке мы явно добавляем специальный символ переноса строки \n, иначе файл формально будет содержать только одну строку текста.

После запуска программы, проверьте, появился ли в папке с программой файл table.txt

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

# открываем файл для записи
table_file = open(file_name, 'r', encoding="utf8")

# получаем список всех строк в файле
file_lines = table_file.readlines()

# перебираем строки в цикле
for line in file_lines:
    # получаем список значений в строке, разделённых пробелом
    values = line.split()
    # сохраняем отдельно x и y
    x = float(values[0])
    y = float(values[1])
    # выводим значения на экран
    print(f"x={x}  y={y}")

table_file.close()

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

Дан файл шифровка.txt состоящий из набора ASCII-кодов, разделённых пробелами. Напишите программу, которая декодирует файл в выводит сообщение на экран.

Скачайте файл шифровка.txt и сохраните его в папке с примером.

Как сохранить файл?

Чтобы сохранить этот файл, щёлкните по ссылке правой кнопкой мыши, и выберите пункт меню Сохранить объект как….

# открываем файл для чтения
with open("шифровка.txt", 'r', encoding="utf8") as file:
    text = file.read() # считываем содержимое файла полностью

    codes = text.split() # получаем список "чисел"

    message = [] # создаём пустой список
    # перебираем все "числа" из кода
    for numStr in codes:
        codeNum = int(numStr)
        message.append(chr(codeNum))

    # получаем из списка букв одну строку
    messageStr = "".join(message)
    print(f"Текст сообщения: {messageStr}")

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

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

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

Пример:

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

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

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

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

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

Скорость печати

Средняя скорость набора - 190 символов в минуту. Свою скорость набора можете проверить на этом сайте.

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

В файле temp.txt хранятся данные о среднегодовой температуре в Минске с 1912 по 2020 годы.

Скачайте файл temp.txt и сохраните его в папке с программой.

Как сохранить файл?

Чтобы сохранить этот файл, щёлкните по ссылке правой кнопкой мыши, и выберите пункт меню Сохранить объект как….

Откройте файл и выведите среднегодовую температуру для представленного диапазона в следующем формате:

...
1999: 7.7 град. Цельсия
2000: 7.8 град. Цельсия
2001: 7.0 град. Цельсия
2002: 7.7 град. Цельсия
2003: 6.4 град. Цельсия
2004: 6.6 град. Цельсия
...

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

...
1979: ##### 5.7
1980: #### 4.8
1981: ###### 6.4
1982: ###### 6.4
1983: ####### 7.3
1984: ###### 6.0
1985: #### 4.5
1986: ##### 5.7
...

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

Дан файл good_data.txt с парами чисел x, y, разделённых пробелом.

Скачайте файл good_data.txt и сохраните его в папке с программой.

Как сохранить файл?

Чтобы сохранить этот файл, щёлкните по ссылке правой кнопкой мыши, и выберите пункт меню Сохранить объект как….

Найти значение выражения \(z=\sqrt{\frac{x}{y}}\). Результаты вычислений запишите в файл func.txt в следующем формате:

...
3.8    2.2    1.3
3.6    2.4    1.2
3.4    2.6    1.1
3.2    2.8    1.1
...

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

Даны два файла, которые содержат одинаковое количество строк. Напишите программу, которая построчно сравнит файлы. Если строки одинаковы, выводится символ =. Если строки отличаются, выводится номер символа, начиная с которого строки не совпадают.

Программу можете проверить с помощью следующих двух файлов - first.txt, second.txt.

Пример (для файлов first.txt и second.txt):

1. =
2. отличие с 11 символа
3. отличие с 16 символа
4. =
5. отличие с 13 символа
6. отличие с 13 символа
7. =
8. =
9. =
10. =
11. =
12. отличие с 18 символа
13. отличие с 19 символа
14. =