# Отчет по теме 6

Коломейцев Дмитрий, А-02-23

## Ввод-вывод данных и операции с файлами

### 1. Установка рабочего каталога. Создание рабочего протокола.

В оболочке IDLE установил рабочий каталог:
![alt text](pics/{72010710-3A40-46AA-BB43-958FFCA4E8BE}.png)


### 2. Вывод данных на экран дисплея.

#### 2.1. Вывод в командной строке.

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

```py
>>> stroka = "Автоматизированная система управления"
>>> stroka
    'Автоматизированная система управления'
```

#### 2.2. Вывод с использованием функции print.

Самый распространённый способ вывода данных на экран - функция print. Она позволяет вывести несколько значений за один вызов.

```py
>>> fff = 234; gg = "Значение температуры ="
>>> print(gg, fff) # Вывод нескольких объектов через запятую
    Значение температуры = 234
```

Через параметр sep можно задать символ (или строку), который будет разделять выводимые элементы.

```py
>>> print(gg, fff, sep = "/") # Вывод объектов с заданным разделителем
    Значение температуры =/234
```
Через параметр end можно указать, что выводить в конце строки вместо перехода на новую строку по умолчанию.

```py
>>> print(gg, fff, sep = "/", end = "***"); print("____") # Вывод объектов с указанным окончанием строки
    Значение температуры =/234***____
```

Функция print поддерживает вывод многострочных строк, которые можно задавать через тройные кавычки, а также можно выводить длинный текст, разбитый на несколько аргументов.

```py
>>> print("""Здесь может выводиться
... большой текст,
... занимающий несколько строк""")
    Здесь может выводиться
    большой текст,
    занимающий несколько строк
```

```py
>>> print("Здесь может выводиться",
... "большой текст",
... "занимающий несколько строк")
    Здесь может выводиться большой текст занимающий несколько строк
```

#### 2.3. Вывод с использованием метода write объекта sys.stdout.

Стандартный способ вывода данных - через поток вывода stdout, находящийся в модуле sys. В данном методе не происходит автоматический переход на новую строку при последовательном его использовании, поэтому необходимо вручную добавлять символ "\n".

```py
>>> import sys
>>> sys.stdout.write("Функция write") # Вывод строки с помощью метода write
    Функция write13 # Число 13 в конце - количество символов в строке
>>> sys.stdout.write("Функция write\n")
    Функция write
    14
```

### 3. Ввод данных с клавиатуры.

Для ввода данных с клавиатуры используется функция input, ранее изученная.

```py
>>> pws = input("Введите пароль: ")
    Введите пароль: 1234567
>>> pws
    '1234567'
>>> type(pws)
    <class 'str'>
```

Ввод значений можно контролировать с помощью циклов и break:

```py
>>> while True:
...     znach = float(input("Задайте коэф. усиления = "))
...     if znach < 17.5 or znach > 23.8:
...         print("Ошибка!")
...     else:
...         break
...   
    Задайте коэф. усиления = 15.4
    Ошибка!
    Задайте коэф. усиления = 21.6
>>>
```

Также с помощью оператора ввода можно вычислять значения математических выражений

```py
>>> import math
>>> print(eval(input("Введите выражение для расчета: ")))
    Введите выражение для расчета: math.log10(23 / (1 + math.exp(-3.24)))
    1.34504378689765
```

### 4. Ввод-вывод при работе с файлами.

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

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

Если файл находится в текущем рабочем каталоге, то для получения полного пути проще сначала получить путь до рабочего каталога. Сделать это можно с помощью функции getcwd модуля os.

```py
>>> import os
>>> os.getcwd()
    '/home/s0ba4/mpei/python-labs/TEMA6'
>>> path = os.getcwd()
>>> path
    '/home/s0ba4/mpei/python-labs/TEMA6'
```

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

```py
>>> os.mkdir("New directory")
>>> os.mkdir("Another new directory")
```

![alt text](pics/{C1999A98-CC84-4CE8-ABD3-60508308BC88}.png)

```py
>>> os.rmdir("Another new directory")
```

![alt text](pics/{9052F00F-49B1-4B6C-915A-DF6D9C0F2826}.png)

```py
>>> os.path.isdir("Another new directory"); os.path.isdir("ABCDEF")
    True
    False
```

Также полный путь доступа к файлу можно получить с помощью отдельной функции abspath. Затем из него можно выделить путь к директории, содержащей файл, и имя самого файла с помощью соответствующих функций dirname и basename.

```py
>>> fil = os.path.abspath("oplata.dbf") # Получение полного пути к файлу
>>> fil
    '/home/s0ba4/mpei/python-labs/TEMA6\\oplata.dbf'
>>> drkt = os.path.dirname(fil) # Выделение пути доступа к файлу
>>> drkt
    '/home/s0ba4/mpei/python-labs/TEMA6'
>>> name = os.path.basename(fil) # Выделение имени файла
>>> name
    'oplata.dbf'
>>> directory, fileName = os.path.split(fil) # Одновременное выделение пути доступа к файлу и его имени
>>> directory
    '/home/s0ba4/mpei/python-labs/TEMA6'
>>> fileName
    'oplata.dbf'
```

Проверка того, указывает ли путь на существующий файл, осуществляется с помощью функции isfile.

```py
>>> os.path.isfile(fil)
    True
>>> os.path.isfile("ABCDEF.txt")
    False
```

#### 4.2. Общая схема работы с файлом.

Для обмена данными с файлом необходимо выполнить следующие операции:
* Открытие файла с указанием его имени и цели (чтение, запись, добавление данных);
* Выполнение одной или нескольких операций обмена данными с файлом;
* Закрытие файла.

#### 4.3. Открытие файла для записи и чтения файла.

Для открытия файла используется функция open, в которой необходимо указывать путь и имя открывающегося файла и цель его использования. Имена аргументов в данной функции можно опускать, но тогда сами аргументы должны идти в правильном порядке. Если же файл находится в текущем рабочем каталоге, то полный путь к нему можно не указывать, будет достаточно только его имени.

Различные значения аргумента mode:
* w - запись/перезапись файла
* w+ - чтение и запись/перезапись файла
* r - только чтение существующего файла
* r+ - чтение и/или запись в существующий файл
* a - запись в конец существующего файла
* a+ - запись в конец существующего файла с возможностью чтения

```py
>>> fp = open(file = drkt + "\\zapis1.txt", mode = "w") # Открытие файла с явным указанием пути и цели использования
>>> fp = open(drkt + "\\zapis1.txt", "w") # Открытие файла без указания имен аргументов
>>> fp = open("zapis1.txt", "w") # Открытие файла, путь к которому совпадает с рабочим каталогом
>>> type(fp)
    <class '_io.TextIOWrapper'>
>>> dir(fp)
    ['_CHUNK_SIZE', 'class', 'del', 'delattr', 'dict', 'dir', 'doc', 'enter', 'eq', 'exit', 'format', 'ge', 'getattribute', 'getstate', 'gt', 'hash', 'init', 'init_subclass', 'iter', 'le', 'lt', 'ne', 'new', 'next', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_finalizing', 'buffer', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'line_buffering', 'mode', 'name', 'newlines', 'read', 'readable', 'readline', 'readlines', 'reconfigure', 'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'write_through', 'writelines']
>>> fp1 = open(drkt + "\\zapis2.bin", "wb+") # Открытие бинарного файла
```

#### 4.4. Закрытие файла.

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

```py
>>> fp.close()
```

#### 4.5. Запись информации в файл.

Стандартный вариант записи в файл - использование метода write.

```py
>>> sps = list(range(1, 13))
>>> sps
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
>>> fp2 = open("zapis3.txt", "w")
>>> fp2.write(str(sps[:4]) + "\n") # Запись в файл первых 4 значений + переход на новую строку
    13
>>> fp2.write(str(sps[4:8]) + "\n")
    13
>>> fp2.write(str(sps[8:]) + "\n")
    16
>>> fp2.close()
```

![alt text](pics/{1C5F9727-9048-44C1-8C12-B6221EEBD909}.png)

Запись данных также можно проводить внутри цикла:

```py
>>> sps3 = [["Иванов И.", 1], ["Петров П.", 2], ["Сидоров С.", 3]]
>>> fp3 = open("zapis4.txt", "w")
>>> for i in range(len(sps3)):
...     stroka4 = sps3[i][0] + " " + str(sps3[i][1])
...     fp3.write(stroka4)
... 
    11
    11
    12
>>> fp3.close()
```

![alt text](pics/{9A4C6E7E-38B4-41F6-96E7-12869DEB96B5}.png)

Данные записались без разделителей, это нужно исправить:

```py
>>> gh = open("zapis5.txt", "w")
>>> for r in sps3:
...     gh.write(r[0] + " " + str(r[1]) + "\n")
...  	
    12
    12
    13
>>> gh.close()
```

![alt text](pics/{26A396C9-A623-47DE-8903-39CBB4436F41}.png)

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

Весь этот цикл можно представить в одной строчке:

```py
>>> for r in sp3: gh.write(r[0] + " " + str(r[1]) + "\n")
```

#### 4.6. Чтение информации из текстового файла внутри цикла.

Чтение данных из файла происходит последовательно, начиная с некоторого символа. 
В качестве примера прочитан ранее созданный файл zapis3.txt:

```py
>>> sps1 = []
>>> fp = open("zapis3.txt")
>>> for stroka in fp:
...     stroka = stroka.rstrip("\n") # Удаление символа \n с конца строки
...     stroka = stroka.replace("[", "")
...     stroka = stroka.replace("]", "")
...     sps1 = sps1 + stroka.split(",")
...   
>>> fp.close()
>>> sps1
    ['1', ' 2', ' 3', ' 4', '5', ' 6', ' 7', ' 8', '9', ' 10', ' 11', ' 12']
```

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

```py
>>> sps2 = []
>>> fp = open("zapis3.txt")
>>> for stroka in fp:
...     stroka = stroka.rstrip("\n")
...     stroka = stroka.replace("[", "").replace("]", "").replace(" ", "")
...     sps2 = sps2 + [int(x) for x in stroka.split(",")]
...    
>>> fp.close()
>>> sps2
... [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
```

#### 4.7. Чтение информации с помощью метода read.

Метод read читает содержимое файла как одну строку.

Если указать аргумент (число), будет прочитано только заданное количество символов, а без аргумента метод возвращает весь оставшийся текст файла, начиная с текущей позиции.

```py
>>> fp = open("zapis3.txt")
>>> stroka1 = fp.read(12) # Чтение первых 12 символов
>>> stroka2 = fp.read() # Чтение файла полностью
>>> fp.close()
>>> stroka1
    '[1, 2, 3, 4]'
>>> stroka2
    '\n[5, 6, 7, 8]\n[9, 10, 11, 12]\n'
```

#### 4.8. Чтение информации с помощью методов readline и readlines.

Метод readline считывает одну строку от текущей позиции.

Повторные вызовы readline читают следующие строки файла.

Метод readlines возвращает список всех строк файла, каждая строка представлена отдельным элементом списка.

```py
>>> fp = open("zapis3.txt")
>>> stroka1 = fp.readline() # Чтение первой строки файла
>>> stroka2 = fp.readline() # Чтение второй строки файла
>>> fp.close()
>>> fp = open("zapis3.txt")
>>> stroka3 = fp.readlines() # Чтение всех строк файла
>>> fp.close()
>>> stroka1
    '[1, 2, 3, 4]\n'
>>> stroka2
    '[5, 6, 7, 8]\n'
>>> stroka3
    ['[1, 2, 3, 4]\n', '[5, 6, 7, 8]\n', '[9, 10, 11, 12]\n']
```

#### 4.9. Ввод-вывод объектов с использованием функции из модуля pickle.

Для работы с бинарными файлами можно пользоваться функциями из модуля pickle.
Примером этого может послужить запись объекта-множества в бинарный файл:

```py
>>> import pickle
>>> mnoz1 = {"pen", "book", "pen", "iPhone", "table", "book"}
>>> fp = open("zapis6.mnz", "wb")
>>> pickle.dump(mnoz1, fp) # Запись объекта в файл
>>> fp.close()
```

Функция pickle.dump записывает объект в файл в бинарном виде, поэтому содержимое такого файла в текстовом редакторе выглядит нечитаемо.

![alt text](pics/{206E90CF-F3FD-42A7-BFCC-ABEC1176FDA2}.png)

Для восстановления объекта из файла применяется функция pickle.load, при этом объект получается в том же виде, как и при записи.

```py
>>> fp = open("zapis6.mnz", "rb")
>>> mnoz2 = pickle.load(fp) # Получение объекта из файла
>>> fp.close()
>>> mnoz2
    {'book', 'iPhone', 'table', 'pen'}
>>> mnoz1 == mnoz2
    True
```

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

```py
>>> fp = open("zapis7.2ob", "wb")
>>> pickle.dump(mnoz1, fp)
>>> pickle.dump(sps3, fp)
>>> fp.close()
>>> fp = open("zapis7.2ob", "rb")
>>> obj1 = pickle.load(fp) # Получение объекта, записанного первым
>>> obj2 = pickle.load(fp) # Получение объекта, записанного вторым
>>> fp.close()
>>> obj1
    {'book', 'iPhone', 'table', 'pen'}
>>> obj2
    [['Иванов И.', 1], ['Петров П.', 2], ['Сидоров С.', 3]]
```

### 5. Перенаправление потоков ввода и вывода данных.

Потоки ввода-вывода можно перенаправлять, например в файл:

```py
>>> import sys
>>> vr_out = sys.stdout # Сохранение текущего потока вывода
>>> fc = open("Stroka.txt", "w")
>>> sys.stdout = fc # Перезапись потока вывода с экрана на файл
>>> print("Запись строки в файл")
>>> fc.close()
>>> sys.stdout = vr_out # Возвращение истинного значения потока вывода
>>> print("Запись строки на экран")
    Запись строки на экран
```

В результате данных действий строка "Запись строки в файл" записалась в файл Stroka.txt:

![alt text](pics/image.png)

Аналогичную операцию можно провести и для потока ввода:

```py
>>> tmp_in = sys.stdin # Сохранение текущего потока ввода
>>> fd = open("Stroka.txt", "r")
>>> sys.stdin = fd
>>> sys.stdin
    <_io.TextIOWrapper name='Stroka.txt' mode='r' encoding='cp1251'>
>>> while True:
...     try:
...         line = input() # Чтение строки из файла
...         print(line)
...     except EOFError:
...         break
... 
    Запись строки в файл
>>> fd.close()
>>> sys.stdin = tmp_in # Возвращение истинного значения потока ввода
```

### 6. Завершение работы со средой.

Сохранил файлы отчета в своем рабочем каталоге и закончил сеанс работы с IDLE.
