{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Branje datotek\n",
    "\n",
    "Ker poskušamo v nekaj ur predavanj strpati celoten tečaj programiranja, pa še marsikaj zraven, se bomo zdaj naučili dveh stvari hkrati: še druge oblike zank in branja datotek.\n",
    "\n",
    "Zanka `while` se je vrtela, dokler je bil resničen določen pogoj. Ta je doslej - in bo pogosto tudi v prihodnje - spraševal po vrednosti kake spremenljivke, ki jo bomo spreminjali znotraj zanke. Tipičen primer je bila zanka, ki je izpisala števila od 1 do 10.\n",
    "\n",
    "```\n",
    "x = 1\n",
    "while x <= 10:\n",
    "    print(x)\n",
    "    x = x + 1\n",
    "```\n",
    "\n",
    "Druga vrsta zanke je `for`. Ta kar sama spreminja spremenljivko: z zanko `for` gremo prek kake reči, na primer vrstic datoteke, elementov nekega seznama, znakov v nekem nizu...\n",
    "\n",
    "Recimo, da imamo datoteko z imenom `teze.txt`, ki vsebuje teže nekega vzorca ljudi; v vsaki vrstici je po ena številka. V teh zapiskih se nahaja v poddirektoriju `datoteke`, torej je njeno ime (relativno glede na tole beležnico) `datoteke/teze.txt`. (Kot ločilo med direktoriji navadno - torej povsod razen na nekaterih mestih v operacijskem sistemu Windows -- uporabljamo navadno poševnico in ne vzvratne.) V datoteki so naslednja števila:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "72\n",
    "85\n",
    "70\n",
    "82\n",
    "50\n",
    "64"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Za začetek le preberimo in izpišimo njene elemente."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "72\n",
      "\n",
      "85\n",
      "\n",
      "70\n",
      "\n",
      "82\n",
      "\n",
      "50\n",
      "\n",
      "64\n"
     ]
    }
   ],
   "source": [
    "teze = open(\"datoteke/teze.txt\")\n",
    "for vrstica in teze:\n",
    "    print(vrstica)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "V prvi vrstici smo poklicali funkcijo `open`, ki odpre datoteko in jo \"vrne\". Kaj pomeni \"vrniti datoteko\"? Pač, vrne nekaj, kar predstavlja odprto datoteko. Spremenljivka `teze` tako ni ne `int` ne `float` ne `str`, temveč gre za spremnljivko tipa ... no, izpišimo jo, pa bomo videli:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<_io.TextIOWrapper name='datoteke/teze.txt' mode='r' encoding='UTF-8'>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "teze"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ja, spremenljivka tipa `_io.TextIOWrapper`. Ni pomembno. Predstavlja pač odprto datoteko.\n",
    "\n",
    "Zanka `for` po vrsticah bere to datoteko. Obrnila se bo tolikokrat, kolikor je vrstic, in spremenljivki `vrstica` vsakič priredila vsebino pravkar prebrane vrstice - kot niz. (Odkod prazne vrstice med njimi? Na koncu vsake vrstice v datoteki je poseben znak, ki pove, da je vrstice konec. Funkcija `print` ga upošteva tako, da gre v novo vrstico. Ker pa gre `print` na koncu izpisa tudi sam od sebe v novo vrstico, dobimo prazne vrstice.)\n",
    "\n",
    "Kaj pa, če bi te nize pretvorili v števila?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "72\n",
      "85\n",
      "70\n",
      "82\n",
      "50\n",
      "64\n"
     ]
    }
   ],
   "source": [
    "teze = open(\"datoteke/teze.txt\")\n",
    "for vrstica in teze:\n",
    "    teza = int(vrstica)\n",
    "    print(teza)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Zdaj pa izračunajmo poprečno težo. Znotraj zanke tež ne bomo izpisovali temveč seštevali, poleg tega pa si bomo zapomnili, koliko tež smo prebrali."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Poprečna teža je 70.5\n"
     ]
    }
   ],
   "source": [
    "n = 0\n",
    "vsota = 0\n",
    "teze = open(\"datoteke/teze.txt\")\n",
    "for vrstica in teze:\n",
    "    teza = int(vrstica)\n",
    "    vsota += teza\n",
    "    n += 1\n",
    "\n",
    "print(\"Poprečna teža je\", vsota / n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Datoteke tečejo\n",
    "\n",
    "Zanka `for` ni edini način za branje datotek. Ne glede na to, kako jih beremo, pa jih lahko beremo le naprej. Skakati nazaj po datoteki je težko ali celo nemogoče. In ko je nekaj prebrano, je prebrano."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "teze = open(\"datoteke/teze.txt\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "85\n",
      "\n",
      "70\n",
      "\n",
      "82\n",
      "\n",
      "50\n",
      "\n",
      "64\n"
     ]
    }
   ],
   "source": [
    "for vrstica in teze:\n",
    "    print(vrstica)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "for vrstica in teze:\n",
    "    print(vrstica)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Druga zanka ne izpiše ničesar, saj se je datoteka `teze` že iztekla."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Pisanje datotek"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ko odpremo datoteko, moramo povedati, ali jo bomo brali ali bomo vanjo pisali. To storimo z dodatnim argumentom, ki je lahko `\"r\"` ali `\"w\"`. Če ga izpustimo - kot smo ga izpustili zgoraj -, bomo datoteko brali.\n",
    "\n",
    "Pa jo zdaj pišimo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "dat = open(\"krneki.txt\", \"w\")\n",
    "dat.write(\"Prva vrstica.\\n\")\n",
    "dat.write(\"Druga vrstica.\\n\")\n",
    "dat.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "V prvi vrstici torej odpremo datoteko in z dodatnim argumentom povemo, da bomo vanjo pisali. Če datoteka s tem imenom že obstaja, jo povozimo.\n",
    "\n",
    "Nato vanjo napišemo dve vrstici. To storimo s funkcijo `write`, ki pa - za razliko od `print`, `input` in `open` - ni funkcija \"kar tako\", temveč pripada datoteki, v našem primeru datoteki `dat`. O teh rečeh bomo več povedali prihodnjič, za zdaj naj zadošča, da vemo, da v datoteko `dat` pišemo tako, da kličemo funkcijo `dat.write`.\n",
    "\n",
    "Funkcija `write` sprejme en argument, ki mora biti niz. Če želimo izpisati število, ga moramo s `str` pretvoriti v niz."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "I/O operation on closed file.",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-22-5561854fa793>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m42\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mdat\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwrite\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m: I/O operation on closed file."
     ]
    }
   ],
   "source": [
    "x = 42\n",
    "dat.write(str(x))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A, ups, v `dat` ne moremo (več) pisati, ker smo jo zaprli, tako da smo v zadnji vrstici poklicali `dat.close`. Tudi `close` je, tako kot `write`, funkcija, ki pripada datoteki `dat`.\n",
    "\n",
    "Čemu je potrebno zapiranje? Python (in večina drugih jezikov) v datoteko ne piše sproti, temveč vse, kar je potrebno zapisati, shranjuje v začasen pomnilnik. Na disk piše šele, ko je ta pomnilnik poln (tedaj zapiše shranjeno in začne shranjevati na novo) ali pa takrat, ko zapremo datoteko.\n",
    "\n",
    "Kaj pa so tisti `\\n` na koncu nizov? To pa je znak za konec vrstice. Brez njega bi se oba niza izpisala v isto vrstico."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Binarne datoteke\n",
    "\n",
    "Nekaterih datotek ni možno brati po vrsticah, saj ne vsebujejo besedila. Še več; besedilne datoteke Python (in drugi jeziki) navadno malo \"popravijo\", da je z njimi lažje delati. Različni operacijski sistemi zapisujejo nekatere znake nekoliko različno, zato je od programskega jezika prijazno, da te stvari poenoti.\n",
    "\n",
    "Če datoteka vsebuje kake nebesedilne podatke, na primer slike ali kake meritve, ki niso zapisane v obliki berljivega besedila, je potrebno Python posvariti, naj datoteko odpre kot \"binarno datoteko\". To storimo tako, da k drugemu argumentu funkcije `open` dodamo še `b`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "slika = open(\"slike/lactuca-sativa.jpg\", \"rb\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Takšnih datotek se ne bomo učili brati, saj ima vsaka čisto drugačno, specifično obliko. Pač pa jih bomo verjetno odpirali zato, da jih bomo dali kot argument kakim funkcijam iz knjižnic, ki jih bomo klicali, ko bomo obdelovali resnične podatke, ne seznamov tež. A več o tem, ko pride na vrsto."
   ]
  }
 ],
 "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.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}