{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "be7bc6cb",
   "metadata": {},
   "source": [
    "# Файлы #"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc8b2eae",
   "metadata": {},
   "source": [
    "На этой лекции мы поговорим с вами о файлах и том, как с ними работать.\n",
    "\n",
    "С файлами, на самом деле, в Python'е никаких проблем не должно возникнуть.\n",
    "Все довольно просто. Чтобы открыть файлы мы используем встроенный метод `open`, встроенную функцию `open`, и передаем ей `filename`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "5974cb39",
   "metadata": {},
   "outputs": [],
   "source": [
    "f = open(\"filename\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aee8d1e2",
   "metadata": {},
   "source": [
    "У нас возвращается файловый объект, с которым мы потом можем работать, для того чтобы записывать данные или читать данные из файлов. \n",
    "\n",
    "Можно их открывать на запись, на чтение, на чтение и запись, и на дозапись. Делается это с помощью модов, которым мы тоже придаем функцию `open`. Например, `a` — это дозапись, `w` — это, очевидно, запись, `r` — это прочтение, `r+` — это запись и чтение одновременно. Точно так же мы можем открывать файл в бинарном виде, то есть работать с бинарными данными, и происходит все аналогично обычному типу. Мы просто добавляем в мод букву `b`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3584b6c2",
   "metadata": {},
   "outputs": [],
   "source": [
    "text_modes = [\"r\", \"w\", \"a\", \"r+\"]\n",
    "binary_modes = [\"br\", \"bw\", \"ba\", \"br+\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83c0ce60",
   "metadata": {},
   "source": [
    "Чтобы открыть файл, например, на запись, мы передаем мод `w` в функцию `open`. Чтобы записать данный файл, мы берем наш файловый объект и пользуемся методом файла `write`, передавая туда строку. В данном случае мы передаем строку, и наш метод `write` возвращает количество символов, которые мы записали. Если это будет байтовая информация, то, собственно, это будет не количество символов, а количество байт. Чтобы закрыть файл, нам нужно вызвать метод `close`, и файл нужно обязательно закрывать."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "2b25c2b5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "47"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = open(\"filename\", \"w\")\n",
    "\n",
    "f.write(\"The world is changed.\\nI taste it in the water.\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ebc3244a",
   "metadata": {},
   "outputs": [],
   "source": [
    "f.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16383eec",
   "metadata": {},
   "source": [
    "Если вы откроете файл и не закроете файл, может произойти что-нибудь страшное и ужасное. На самом деле нет, но принято файлы закрывать, и мы поговорим с вами о том, как с этим работать. Итак, чтобы открыть файл на чтение и запись, нам нужно использовать `r+`, и мы можем читать данные из файла с помощью метода `read`. `Read` по умолчанию читает столько, сколько сможет. Если файл не поместится в памяти, то это ваши проблемы. Вы также можете указать в методе `read` конкретное количество информации, которое вы хотите прочитать, передав `size`, но по умолчанию читается весь файл и выводится, собственно."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "9d740b8c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The world is changed.\\nI taste it in the water.\\n'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = open(\"filename\", \"r+\")\n",
    "f.read()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "aee2da15",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "49"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f.tell()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d4c7a2b",
   "metadata": {},
   "source": [
    "Здесь мы выводим все строчки, которые туда записали, и видим, что на самом деле информация в файл попала. Очень важный момент. Когда мы прочитали весь файл, у нас указатель того, где мы сейчас находимся в файле — в самом конце. В данном случае это 47 символов. Если мы попробуем прочитать еще раз, то мы ничего не найдем, потому что мы весь файл уже прочитали и у нас пойнтер в самом конце."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "cf719f78",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "''"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f.read()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b0798a6",
   "metadata": {},
   "source": [
    "Для того чтобы прочитать его, например, заново, нам нужно использовать метод `seek` и перенести указатель на начало файла. Как вы видите, он равен нулю, и теперь мы можем действительно читать данные заново и, например, опять же закрыть файл, потому что файлы всегда нужно закрывать."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "57b6f5bb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f.seek(0)\n",
    "f.tell()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "4ce93652",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The world is changed.\n",
      "I taste it in the water.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(f.read())\n",
    "f.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8109309b",
   "metadata": {},
   "source": [
    "Собственно, кроме обычного метода `read`, есть также полезные методы для работы со строками, которые позволяют вам читать строки, одну, например, или несколько.\n",
    "\n",
    "Чтобы прочитать конкретно одну строку, можно использовать метод `readline` у того же файлового объекта, и метод вернет строку, разбив по символу переноса строки. Как видите, у нас вернулась только первая строка без второй."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "1a2fd52d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The world is changed.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "f = open(\"filename\", \"r+\")\n",
    "print(f.readline())\n",
    "f.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16da382f",
   "metadata": {},
   "source": [
    "Если вам интересно прочитать сразу все строки, разбить их по символу переноса строки и записать все это, например, в список, можно использовать метод `readlines`. Он сделает именно это — вернет список строк, разбитых по символу перевода строки."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "1d65e32e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['The world is changed.\\n', 'I taste it in the water.\\n']"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = open(\"filename\", \"r+\")\n",
    "f.readlines()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9fb151d1",
   "metadata": {},
   "source": [
    "Если мы закроем файл и попробуем его прочитать, очевидно, у нас ничего не получится, потому что закрытый файл прочитать нельзя. Будьте внимательны."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "13c0a8d3",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "I/O operation on closed file.",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-14-bf012af3c351>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m: I/O operation on closed file."
     ]
    }
   ],
   "source": [
    "f.close()\n",
    "f.read()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ac70071",
   "metadata": {},
   "source": [
    "На самом деле, я рекомендую вам работать с файлами немного другим образом. Существует специальная вещь, называемая контекстный менеджер, который вам позволяет не заботиться о закрытии файлов. Вы можете открыть файл с помощью оператора `with`, и записать в файловый объект переменную `f` и потом работать с ним внутри этого контекстного блока и не закрывать его, потому что контекстный менеджер заботится об этом за вас."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "ed64d12d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The world is changed.\n",
      "I taste it in the water.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "with open(\"filename\") as f:\n",
    "    print(f.read())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7318dd16",
   "metadata": {},
   "source": [
    "Про контекстный менеджер мы поговорим позднее, а пока просто можете использовать эту конструкцию и не заботиться о том, чтобы закрывать файл.\n",
    "\n",
    "Итак, с файлами в Python работать довольно просто. У нас есть файловые объекты, мы можем в них писать, из них читать. Не забывайте закрывать файлы или используйте контекстный менеджер."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
