> For the complete documentation index, see [llms.txt](https://timosii.gitbook.io/py_tutorial/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://timosii.gitbook.io/py_tutorial/faily/rabota-s-failami-v-python.md).

# Работа с файлами в Python

### Открытие файла

```python
файловая_переменная = open(имя_файла, режим, кодировка)
```

* Файловая переменная — имя переменной, которая ссылается на файловый объект
* Имя файла —  строковый литерал, задающий имя файла
* Режим —  строковый литерал, задающий режим доступа (чтение, запись и т.д.), в котором файл будет открыт
* Кодировка — тип кодировки (например, UTF-8 при работе с текстовыми файлами)

#### Режимы

* **r**: **чтение**&#x20;
  * Поток будет открыт *в режиме чтения*
  * Файл, связанный с потоком *должен существовать* и быть доступным для чтения, в противном случае, функция **open()** вызывает исключение
* **w**: **запись**&#x20;
  * Поток будет открыт *в режиме записи*
  * Файл, связанный с потоком, *не обязан существовать*. Если его не существует, он будет создан. Если существует, он будет обрезан до нулевой длины (стерт). Если создание невозможно (например, из-за системных разрешений) функция **open()** вызывает исключение.&#x20;
* **a**: **дозапись**&#x20;
  * Поток будет открыт *в режиме дозаписи*
  * Файл, связанный с потоком, *не обязан существовать*. Если его не существует, он будет создан. Если существует, виртуальная записывающая головка будет установлена в конец файла (предыдущее содержимое файла останется без изменений)&#x20;
* **r+**: **чтение и обновление**
  * Поток будет открыт *в режиме чтения и обновления*&#x20;
  * Файл, связанный с потоком, *должен существовать и быть доступным для записи*, в противном случае функция **open()** вызывает исключение
  * Операции чтения и записи разрешены для потока
* **w+**: **запись и обновление**&#x20;
  * Поток будет открыт в режиме *записи и обновления*
  * Файл, связанный с потоком, *не обязан существовать*. Если его не существует, он будет создан. Предыдущее содержимое файла остается нетронутым&#x20;
  * Операции чтения и записи разрешены для потока

Есть два типа режимов: **текстовый** и **бинарный**

Текстовый режим — для работы с текстом. Бинарный — для работы с другими типами данных.

<figure><img src="/files/vynbXZMgjgyxfKRUVTcC" alt=""><figcaption><p>Режимы</p></figcaption></figure>

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

{% code overflow="wrap" %}

```python
# открываем файл для чтения
test_file = open('test.txt', 'r') 
# убедитесь, что файл существует
# переменная test_file будет ссылаться на файловый объект, который можно использовать для чтения
# открываем файл для записи
test_file = open('test.txt', 'w') 
# если файл существует, его содержимое будет удалено
# переменная test_file будет ссылаться на файловый объект, который можно использовать для записи
test_file = open(r'C:\Users\temp\test.txt', 'w')
# префикс r указывает на raw-строку, которую не следует форматировать
# без него интерпретатор предположит, что символы обратной косой черты являются частью экранированных последовательностей, и произойдёт ошибка
```

{% endcode %}

### Запись данных в файл

После открытия файла для выполнения операций с файлом используются **методы файлового объекта**

```python
файловая_переменная.write(строковое_значение)
```

* Файловая переменная — это переменная, которая ссылается на файловый объект
* Строковое значение — символьная последовательность, которая будет записана в файл
* Файл должен быть открыт для записи, либо произойдёт ошибка

```python
test_file.write("Hello, world!")
# ниже вариант с переменной
name = "Petrov Ivan"
test_file.write(name)
```

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

После работы с файлом нужно применить метод файлового объекта **close()**

Это действие *разрывает связь программы с файлом*

```python
test_file.close()
```

***Практика:***

1. Напишите программу, которая записывает в файл три строковых значения — название страны и её столицу, например: "Россия: Москва"

* Порядок действия следующий: файл должен открыться на запись, далее происходит запись трёх переменных, потом файл закрывается

2. Напишите функцию, которая принимает на вход словарь и строковое значение — название файла (итого два аргумента). В функции должна произойти запись в виде "ключ: значение" элементов словаря. Название файла, который нужно создать — второй аргумент функции.

{% code overflow="wrap" %}

```python
# пример данных, поступающих на вход
test_dict = {'Russia': 'Moscow'}
file_name = 'hello.txt'
# пример вызова функции
write_dict(test_dict, file_name)
# в результате создаётся файл с именем 'hello.txt' и содержимым 'Russia: Moscow'
```

{% endcode %}

### Чтение данных из файла

Если файл был открыт для чтения, то для чтений всего его содержимого в оперативную память применяют метод файлового объекта **read()**

При вызове метода **read()** он возвращает содержимое файла в качестве *строкового значения*

```python
def main():
    # открыть файл с именем test.txt
    infile = open('test.txt', 'r')
    # прочитать содержимое файла
    file_contents = infile.read()
    # закрыть файл
    infile.close()
    # напечатать данные, считанные в оперативную память
    print(file_contents)

main()
```

***Практика:***

* Создайте файл, сохраните в нём рецепт любого блюда
* Прочитайте содержимое и напечатайте на экран

При вызове метода **read()** содержимое файла считывается полностью. Но часто программам требуется читать и обрабатывать хранящиеся в файле значения поочередно.

Для этого применяется метод **readline()**. Строка файла представляет собой символьную последовательность, завершающуюся символом *\n*. Этот метод возвращает строку файла как символьную последовательность, включая *\n*

```python
def main():
    # открыть файл с именем test.txt
    infile = open('test.txt', 'r')
    # прочитать содержимое файла
    line1 = infile.readline()
    line2 = infile.readline()
    line3 = infile.readline()
    # закрыть файл
    infile.close()
    # напечатать данные, считанные в оперативную память
    print(line1)
    print(line2)
    print(line3)
    

main()
```

Как Python понимает, что нужно считывать следующую строку? Когда файл открыт для чтения, для этого файла внутренне поддерживается специальное значение, которое называется **позицией считывания.** Она отмечает положение следующего значения, которое будет прочитано из файла.

* Первоначально позиция считывания находится в начале файла.&#x20;
* После каждого вызова метода **readline()** она смещается на позицию после символа **\n** в файле

#### Конкатенация символа новой строки со строковым значением

```python
def main():
    # получаем три имени
    print("Введите имена трех друзей: ")
    name1 = input('Друг №1: ')
    name2 = input('Друг №2: ')
    name3 = input('Друг №3: ')
    
    # открыть файл с именем friends.txt
    myfile = open('friends.txt', 'w')
    
    # записать имена в файл
    myfile.write(name1 + '\n')
    myfile.write(name2 + '\n')
    myfile.write(name3 + '\n')
    
    # закрыть файл
    myfile.close()
    print('Имена были записаны в friends.txt')
    
    
main()
```

### Дозапись данных в существующий файл

Когда для открытия файла вывода используется режим **'w'** и файл с указанным именем уже на диске существует, имеющийся файл будет удален, и будет создан новый пустой файл с тем же именем

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

В Python режим 'a' используется для открытия файла вывода *в режиме дозаписи*, то есть:

* Если файл уже существует, он не будет стерт, если файл отсутствует, он будет создан
* Когда данные пишутся в файл, они будут дописываться в конец текущего содержимого файла

***Практика:***

* Создайте файл с текстом
* В режими дозаписи добавьте в него данные
* Проверьте, как изменилось содержимое файла

### Работа с числами

Числа из файлов всегда читаются в формате **str**

При записи в файл число нужно преобразовать в строку

Для этого используйте преобразование типов — функцию **str()**:

```python
# пример работы с числами
a = 5
b = 11
s = a + b
# преобразование числа при помощи функции str()
out = str(s) # '16'
# out - это строка, её можно записывать в файл
```

Обратное преобразование — при помощи функции **int():**

```python
infile = open('numbers.txt', 'r')
value = int(infile.readline())
infile.close()
```

***Интерактив:***

* Какие три шага программа должна сделать, когда она использует файл?
* Что присходит с уже существующим файлом при попытке открыть его как файл вывода (в режиме 'w')?
* Какова задача открытия файла? Какова задача закрытия файла?
* Что такое позиция считывания файла? Где она находится первоначально при открытии файла ввода?

### Применение циклов для обработки файлов

Файлы обычно содержат большие объёмы данных, и в программах, как правило, применяется цикл, в котором обрабатываются данные, хранящиеся в файле

```python
# программа позволяет пользователю ввести суммы продаж
# и записывает эти суммы в файл sales.txt

def main():
    # получить количество дней
    num_days = int(input("Продажи за какое количество дней " +
                        "вы хотите внести? "))
    # открыть новый файл
    sales_file = open("sales.txt", 'w')
    # получить суммы продаж за каждый день
    # и записать их в файл
    for count in range(1, num_days + 1):
       # получить продажи за день
       sales = float(input(f'Введите продажи за день № {count}: '))
       # записать сумму продаж в файл
       sales_file.write(f'{sales}\n')
    # закрыть файл
    sales_file.close()
    print('Данные записаны в sales.txt')
```

Мы знакомы с методом **readline()** для чтения файлов построчно

Если мы не знаем размер файла, мы можем воспользоваться циклом для определения конца файла. Метод **readline()** возвращает пустую строку, когда достигает конца файла.

```python
# программа читает все значения из файла sales.txt

def main():
    # открыть файл sales.txt для чтения
    sales_file = open("sales.txt", 'r')
    # прочитать первую строку из файла, но пока не конвертировать в число
    # сначала нужно выполнить проверку на пустое строковое значение
    line = sales_file.readline()
    # продолжать обработку до тех пор, пока из readline
    # не будет возвращена пустая строка
    while line != '':
        # конвертировать строку в число с плавающей точкой
        amount = float(line)
        # отформатировать и показать сумму
        print(f'{amount:.2f}')
        # прочитать следующую строку
        line = sales_file.readline()
    # закрыть файл
    sales_file.close()
```

Python позволяет итерироваться по файловому объекту. Так нам не нужно думать о том, когда будет достигнут конец файла — цикл закончится сам

```python
# программа читает все значения из файла sales.txt

def main():
    # открыть файл sales.txt для чтения
    sales_file = open("sales.txt", 'r')
    # прочитать все строки из файла
    for line in sales_file:
        # конвертировать строку в число с плавающей точкой
        amount = float(line)
        # отформатировать и показать сумму
        print(f'{amount:.2f}')
    # закрыть файл
    sales_file.close()
```

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

### Менеджеры контекста
