7. Textové súbory

So súbormi súvisia znakové reťazce ale aj príkazy input() a print() na vstup a výstup:

  • znakové reťazce sú postupnosti znakov (v kódovaní Unicode), ktoré môžu obsahovať aj znaky konca riadka '\n'

  • funkcia input() prečíta zo štandardného vstupu znakový reťazec, t.j. číta z klávesnice

  • funkcia print() zapíše reťazec na štandardný výstup, t.j. do textového konzolového okna

Textový súbor

Je postupnosť znakov, ktorá môže obsahovať aj znaky konca riadka. Väčšinou je táto postupnosť uložená na disku v súbore.

Na textový súbor sa môžeme pozerať ako na postupnosť riadkov (môže to byť aj prázdna postupnosť), pričom každý riadok je postupnosťou znakov (znakový reťazec), ktorá je ukončená špeciálnym znakom '\n'.

So súbormi sa vo všeobecnosti pracuje takto:

  • najprv musíme vytvoriť spojenie medzi našim programom a súborom, ktorý je veľmi často v nejakej externej pamäti - tomuto hovoríme otvoriť súbor

  • teraz sa dá so súborom pracovať, t.j. môžeme z neho čítať, alebo do neho zapisovať

  • keď so súborom skončíme prácu, musíme zrušiť spojenie, hovoríme tomu zatvoriť súbor

Čítanie zo súboru

Najprv sa naučíme čítať zo súboru, čo označuje, že postupne sa náš program dozvedá, aký je obsah súboru.

Otvorenie súboru na čítanie

Súbor otvárame volaním štandardnej funkcie open(), ktorej oznámime meno súboru, ktorý chceme čítať. Táto funkcia vráti referenciu na súborový objekt (hovoríme tomu aj dátový prúd, t.j. stream):

premenná = open('meno_súboru', 'r')

Do súborovej premennej sa priradí spojenie s uvedeným súborom. Najčastejšie je tento súbor umiestnený v tom istom priečinku, v ktorom sa nachádza samotný Python skript. Meno súboru môže obsahovať aj celú cestu k súboru, prípadne môže byť relatívna k umiestneniu skriptu.

Meno súborovej premennej je vhodné voliť tak, aby nejako zodpovedalo vzťahu k súboru, napr.

subor = open('pribeh.txt', 'r')
kniha = open('c:/dokumenty/python.txt', 'r')
file = open('../texty/prvy.txt', 'r')

V týchto príkladoch otvárania súborov vidíte, že meno súboru môže byť kompletná cesta 'c:/dokumenty/python.txt' alebo relatívna k pozícii skriptu '../texty/prvy.txt'.

Čítanie zo súboru

Najčastejšie sa informácie zo súboru čítajú po celých riadkoch. Možností, ako takto čítať je viac. Základný spôsob je:

riadok = subor.readline()

Funkcia readline() je metódou súborovej premennej, preto za meno súborovej premennej píšeme bodku a meno funkcie. Funkcia vráti znakový reťazec - prečítaný riadok aj s koncovým znakom '\n'. Súborová premenná si zároveň zapamätá, kde v súbore sa práve nachádza toto čítanie, aby každé ďalšie zavolanie readline() čítalo ďalšie a ďalšie riadky.

Funkcia vráti prázdny reťazec '', ak sa už prečítali všetky riadky a teda pozícia čítania v súbore je na konci súboru.

Zrejme prečítaný riadok nemusíme priradiť do premennej, ale môžeme ho spracovať aj inak, napr.

subor = open('subor.txt', 'r')
print(subor.readline())
print('dlzka =', len(subor.readline()))
print(subor.readline()[::-1])

V tomto programe sa najprv vypíše obsah prvého riadka, potom dĺžka druhého riadka (aj s koncovým znakom '\n') a na záver sa vypíše tretí riadok ale otočený (aj s koncovým znakom '\n', ktorý sa vypíše ako prvý).

Zatvorenie súboru

Keď skončíme prácu so súborom, uzavrieme otvorené spojenie volaním:

subor.close()

Tým sa uvoľnia všetky systémové zdroje (resources), ktoré boli potrebné pre otvorený súbor. Zrejme so zatvoreným súborom sa už nedá ďalej pracovať a napr. čítanie by vyvolalo chybovú správu.

Ďalej ukážeme, ako môžeme pracovať s textovým súborom. Predpokladajme, že máme pripravený nejaký textový súbor, napr. 'subor.txt':

Od ucenia este
nikto nezomrel,
  ale naco riskovat.

Albert Einstein

Tento súbor má 5 riadkov (štvrtý je prázdny) a preto ho môžeme celý prečítať a vypísať takto:

t = open('subor.txt', 'r')

for i in range(5):
    riadok = t.readline()
    print(riadok)

t.close()

program vypíše:

Od ucenia este

nikto nezomrel,

  ale naco riskovat.


Albert Einstein

Keďže metóda readline() prečíta zo súboru celý riadok aj s koncovým '\n', príkaz print() k tomu pridáva ešte jeden svoj '\n' a preto je za každým vypísaným riadkom ešte jeden prázdny. Buď príkazu print() povieme, aby na koniec riadka nevkladal prechod na nový riadok (napr. print(riadok, end='')), alebo pred samotným výpisom z reťazca riadok vyhodíme posledný znak, napr.

t = open('subor.txt', 'r')
for i in range(5):
    riadok = t.readline()
    print(riadok[:-1])
t.close()

Takéto vyhadzovanie posledného znaku z reťazca môže nefungovať celkom správne pre posledný riadok súboru, ktorý nemusí byť ukončený znakom '\n'.

Zistenie konca súboru

Najväčším nedostatkom predchádzajúceho programu je to, že predpokladá veľkosť vstupného súboru presne 5 riadkov. Ak by sme tento počet dopredu nepoznali, musíme použiť nejaký iný spôsob. Keďže metóda readline() vráti na konci súboru prázdny reťazec '' (pozor, nie jednoznakový reťazec '\n'), môžeme práve túto podmienku využiť na testovanie konca súboru:

t = open('subor.txt', 'r')
riadok = t.readline()
while riadok != '':
    print(riadok, end='')
    riadok = t.readline()
t.close()

Tento program už správne vypíše všetky riadky súboru, hoci nevidíme, či je štvrtý riadok prázdny alebo obsahuje aj nejaké medzery:

Od ucenia este
nikto nezomrel,
  ale naco riskovat.

Albert Einstein

šablóna čítania s while-cyklom

Takto budú často vyzerať naše programy, ktoré budú čítať súbor po riadkoch:

subor = open('meno súboru', 'r')

riadok = subor.readline()
while riadok != '':
    # ... spracuj riadok
    riadok = subor.readline()

subor.close()

Môžeme to prepísať aj s použitím break:

t = open('subor.txt', 'r')
while True:
    riadok = t.readline()
    if riadok == '':
        break
    print(riadok, end='')
t.close()

Niekedy sa nám môže hodiť taký výpis prečítaného reťazca, ktorý napr. zobrazí nielen medzery na konci reťazca, ale aj ukončovací znak '\n'. Využijeme na to štandardnú funkciu repr().

funkcia repr()

Volanie štandardnej funkcie:

repr(reťazec)

vráti takú reťazcovú reprezentáciu daného parametra, aby sme po jeho vypísaní (napr. funkciou print()) dostali presný taký tvar, aký očakáva Python pri zadávaní konštanty, teda aj s apostrofmi, prípadne aj so znakom '\' pri špeciálnych znakoch.

Môže sa použiť aj pri ladení a testovaní, lebo máme lepší prehľad o skutočnom obsahu reťazca. Napr.

>>> a = 'ahoj   \naj "apostrof" \' v texte  \n'
>>> print(a)
ahoj
aj "apostrof" ' v texte

>>> print(repr(a))
'ahoj   \naj "apostrof" \' v texte  \n'

Doplníme do while-cyklu o volanie funkcie repr():

t = open('subor.txt', 'r')
riadok = t.readline()
while riadok != '':
    print(repr(riadok))
    riadok = t.readline()
t.close()

Po spustení vidíme, že sa vypíše:

'Od ucenia este\n'
'nikto nezomrel,   \n'
'  ale naco riskovat.\n'
'\n'
'Albert Einstein\n'

Namiesto while riadok != '': môžeme zapísať while riadok:.

Vidíme, že druhý riadok obsahuje medzery aj na konci riadka. Ak by sme pri čítaní súboru nepotrebovali informácie o medzerách na začiatku a konci riadkov, môžeme využiť reťazcovú metódu strip():

t = open('subor.txt', 'r')
riadok = t.readline()
while riadok:
    print(repr(riadok.strip()))
    riadok = t.readline()
t.close()

vypíše:

'Od ucenia este'
'nikto nezomrel,'
'ale naco riskovat.'
''
'Albert Einstein'

Všimnite si, že takto sme sa zbavili aj záverečného znaku '\n'. Ak by sme namiesto riadok.strip() použili riadok.rstrip(), vyhodia sa medzerové znaky len od konca reťazca (sprava) a na začiatku riadkov medzery ostávajú.

Použitie for-cyklu pre čítanie zo súboru

Python umožňuje použiť for-cyklus, aj pre súbory, o ktorých dopredu nevieme, koľko majú riadkov. For-cyklus má vtedy tvar:

for riadok in súborová_premenná:
    prikazy

kde riadok je ľubovoľná premenná cyklu, do ktorej sa budú postupne priraďovať všetky prečítané riadky - POZOR! aj s koncovým '\n', súborová_premenná musí byť otvoreným súborom na čítanie.

Program sa teraz výrazne zjednoduší:

t = open('subor.txt', 'r')
for riadok in t:
    print(repr(riadok))
t.close()

šablóna čítania s for-cyklom

S použitím for-cyklu môžu byť naše programy, ktoré čítajú súbor po riadkoch, ešte čitateľnejšie:

subor = open('meno súboru', 'r')

for riadok in subor:
    # ... spracuj riadok

subor.close()

Takýto for-cyklus bude fungovať aj vtedy, keď sme už zo súboru niečo čítali a potrebujeme spracovať už len zvyšok súboru, napr.

t = open('subor.txt', 'r')
riadok = t.readline()
print('najprv som precital:', repr(riadok.rstrip()))
print('v subore ostali este tieto riadky:')
for riadok in t:
    print(repr(riadok.rstrip()))
t.close()

Teraz sa vypíše:

najprv som precital: 'Od ucenia este'
v subore ostali este tieto riadky:
'nikto nezomrel,'
'ale naco riskovat.'
''
'Albert Einstein'

Prečítanie celého súboru do jedného reťazca

Zapíšme riešenie takejto úlohy: do jednej reťazcovej premennej prečítame všetky riadky súboru, pričom im ponecháme koncové '\n'. Zrejme, ak by sme takýto reťazec naraz celý vypísali (pomocou print()), dostali by sme kompletný výpis. Napr.

t = open('subor.txt', 'r')
cely_subor = ''
for riadok in t:
    cely_subor = cely_subor + riadok
t.close()
print(cely_subor, end='')

Všimnite si, že riadok programu cely_subor = cely_subor + riadok by sme mohli zapísať aj takto cely_subor += riadok

To, čo sme prácne skladali cyklom, za nás urobí metóda read(), teda

t = open('subor.txt', 'r')
cely_subor = t.read()
t.close()
print(cely_subor, end='')

Samozrejme, takéto skladanie súboru do jednej reťazcovej premennej môžeme urobiť len vtedy, ak spracovávaný súbor nie je väčší ako kapacita pamäte pre Python (závisí to od vášho počítača, ale je to od niekoľkých 100MB po GB).

metóda súbor.read()

súbor.read(počet_znakov)
súbor.read()
Parametre

počet_znakov – určuje počet znakov, ktoré budem chcieť zo suboru prečítať

Metóda prečíta zo súboru a vráti ako výsledok funkcie zadaný počet znakov. Ak už v súbore toľko znakov nie je, alebo sme nezadali počet znakov, vráti maximálny možný počet (alebo aj prázdny reťazec). Napr.

>>> t = open('subor.txt')
>>> print('prvy znak =', repr(t.read(1)))
>>> print('dalsich 10 znakov =', repr(t.read(10)))
>>> print('zvysok suboru =', repr(t.read()))

Slovenčina v súbore

Hoci znakové reťazce v Pythone sú ukladané v kódovaní Unicode, pri práci so súbormi, ktoré obsahujú znaky s diakritikou, musíme upresniť aj kódovanie v súbore. Samotné súbory môžu mať pri uložení na disku rôzne kódovania (závisí to aj od vášho operačného systému), napr. 'cp1250', 'iso88591', 'utf-8', … a pri ich otváraní treba toto kódovanie uvádzať ako parameter funkcie open(). Súbory, ktoré dostanete na čítanie v tomto kurze, budú mať väčšinou kódovanie 'utf-8', ale vaše vlastné súbory môžu mať aj iné kódovanie.

Preto súbor s diakritikou najčastejšie otvárame takto:

subor = open(meno_suboru, 'r', encoding='utf-8')

Zápis do súboru

Doteraz sme čítali už existujúci súbor. Teraz sa naučíme textový súbor aj vytvárať. Bude to veľmi podobné ako pri čítaní súboru.

Otvorenie súboru

do súborovej premennej sa priradí spojenie so súborom:

subor = open('meno_súboru', 'w')

Súbor bude umiestnený v tom istom priečinku, kde sa nachádza samotný Python skript (resp. treba uviesť cestu). Ak tento súbor ešte neexistoval, tento príkaz ho vytvorí (vytvorí sa prázdny súbor). Ak takýto súbor už existoval, tento príkaz ho vyprázdni. Treba si dávať pozor, lebo omylom môžeme prísť o dôležitý súbor.

Možností, ako zapisovať riadky do súboru je viac. My si postupne ukážeme dva z nich: zápis pomocou základnej metódy pre zápis write() a pomocou nám známej štandardnej funkcie print(). Najprv metóda write():

Zápis do súboru

Zápis nejakého reťazca do súboru urobíme pomocou volania:

subor.write(reťazec)

Táto metóda zapíše zadaný reťazec na momentálny koniec súboru. Ak chceme, aby sa v súbore objavili aj koncové znaky '\n', musíme ich pridať do reťazca.

Niekoľko za sebou idúcich zápisov do súboru môžeme spojiť do jedného, napr.

subor.write('Py')
subor.write('thon\nje')
subor.write(' najlepsi\n')

môžeme zapísať jediným volaním metódy write():

subor.write('Python\nje najlepsi\n')

Zatvorenie súboru

Tak ako pri čítaní súboru sme na záver súbor zatvárali, musíme zatvárať súbor aj pri vytváraní súboru:

subor.close()

Metóda skončí prácu so súborom, t.j. zruší spojenie s fyzickým súborom na disku. Bez volania tejto metódy nemáme zaručené, že Python naozaj fyzicky stihol zapísať všetky reťazce z volania write() na disk. Tiež operačný systém by mohol mať problém so znovu otvorením ešte nezatvoreného súboru.

Zápis do súboru ukážeme na príklade, v ktorom vytvoríme niekoľko riadkový súbor 'subor1.txt':

subor = open('subor1.txt', 'w')
subor.write('zoznam prvocisel:\n')
for ix in 2, 3, 5, 7, 11, 13:
    subor.write(f'cislo {ix} je prvocislo\n')
subor.close()

Program najprv do súboru zapísal jeden riadok ‚zoznam prvocisel:‘ a za ním ďalších 6 riadkov:

zoznam prvocisel:
cislo 2 je prvocislo
cislo 3 je prvocislo
cislo 5 je prvocislo
cislo 7 je prvocislo
cislo 11 je prvocislo
cislo 13 je prvocislo

Zápis do súboru pomocou print()

Doteraz sme štandardný príkaz print() používali na výpis do textovej plochy Shellu. Veľmi jednoducho, môžeme presmerovať výstup z už odladeného programu do súboru.

Program vytvorí súbor 'nahodne_cisla.txt', do ktorého zapíše pod seba 100 náhodných čísel:

import random
subor = open('nahodne_cisla.txt', 'w')
for i in range(100):
    print(random.randint(1, 100), file=subor)
subor.close()

Všimnite si nový parameter pri volaní funkcie print(), pomocou ktorého presmerujeme výstup do nášho súboru (tu musíme uviesť súborovú premennú už otvoreného súboru na zápis).

Ak by sme chceli, aby boli čísla v súbore nie v jednom stĺpci ale v jednom riadku oddelené medzerou, zapísali by sme:

import random
subor = open('nahodne_cisla.txt', 'w')
for i in range(100):
    print(random.randint(1, 100), end=' ', file=subor)
subor.close()

Kopírovanie súboru

Ak potrebujeme obsah jedného súboru prekopírovať do druhého (pritom možno niečo spraviť s každým riadkom), môžeme použiť 2 súborové premenné, napr.

odkial = open('subor.txt', 'r')
kam = open('subor2.txt', 'w')
for riadok in odkial:
    riadok = riadok.strip()
    if riadok != '':
        kam.write(riadok + '\n')
odkial.close()
kam.close()

Program postupne prečíta všetky riadky, vyhodí medzery zo začiatku a z konca každého riadka, a ak je takýto riadok neprázdny, zapíše ho do druhého súboru (keďže strip() vyhodil z riadka aj koncové '\n', museli sme ho tam vo write() pridať).

Táto istá úloha by sa dala riešiť aj pomocou jednej súborovej premennej - najprv súbor čítame a do jednej reťazcovej premennej pripravujeme obsah nového súboru, nakoniec ho celý zapíšeme:

t = open('subor.txt', 'r')
cely = ''
for riadok in t:
    riadok = riadok.strip()
    if riadok != '':
        cely += riadok + '\n'
t.close()
t = open('subor2.txt', 'w')
t.write(cely)
t.close()

Ak by sme pri kopírovaní riadkov nepotrebovali meniť nič, môžeme použiť metódu read(), napr.

t = open('subor.txt', 'r')
cely = t.read()
t.close()
t = open('subor2.txt', 'w')
t.write(cely)
t.close()

Na prácu so súbormi môžeme využiť špeciálnu programovú konštrukciu, pomocou ktorej bude Python vedieť, že sme už so súborom skončili pracovať a teda ho treba zatvoriť. Samotný príkaz má aj iné využitie ako pre prácu so súbormi, ale v tomto kurze sa s tým nestretneme.

Konštrukcia with

Všeobecný tvar príkazu je:

with open(...) as premenna:
    prikaz
    prikaz
    ...

Touto príkazovou konštrukciou sa otvorí požadovaný súbor a referencia na súbor sa priradí do premennej uvedenej za as. Ďalej sa vykonajú všetky príkazy v bloku a po ich skončení sa súbor automaticky zatvorí. Urobí sa skoro to isté, ako

premenna = open(...)
prikaz
prikaz
...
premenna.close()

Odporúčame pri práci so súbormi používať čo najviac práve túto konštrukciu, čo oceníme napr. aj prácu so súbormi vo funkciách, v ktorých príkaz return, ak sa použije vo vnútri bloku with, automaticky zatvorí otvorené súbory.

Ukážme niekoľko príkladov zápisu pomocou with:

  1. Prečítaj a vypíš obsah celého súboru:

    with open('subor.txt') as subor:
        print(subor.read())
    
  2. Vytvor súbor s tromi riadkami:

    with open('subor.txt','w') as file:
        print('prvy\ndruhy\ntreti\n', file=file)
    

    Všimnite si tu použitie mena súborovej premennej: nazvali sme ju file rovnako ako meno parametra vo funkcii print(), preto musíme presmerovanie do súboru zapísať ako print(..., file=file): formálnemu parametru file priradíme hodnotu skutočného parametra file.

  3. Vytvor súbor 100 náhodných čísel:

    import random
    with open('cisla.txt','w') as file:
        for i in range(100):
            file.write(str(random.randrange(1000))+' ')
    

Automatické zatváranie súboru

Python sa v jednoduchých prípadoch snaží korektne zatvoriť otvorené súbory, keď už sme s nimi skončili pracovať a pritom sme nepoužili metódu close(). V serióznych aplikáciách toto nebudeme používať, ale pri jednoduchých testoch a ukážkach sa to objaviť môže.

V nasledovných príkladoch využívame to, že funkcia open() vracia ako výsledok súborovú premennú, t.j. spojenie na súbor. Ak toto spojenie potrebujeme použiť len jednorázovo, nemusíme to priradíme do premennej, ale použijeme ho priamo napr. s volaním nejakej metódy.

Ak do súboru zapisujeme len jedenkrát a hneď ho zatvárame, nemusíme na to vytvárať súborovú premennú, ale priamo pri otvorení urobíme jeden zápis. Vtedy sa súbor automaticky zatvorí. Napr.

>>> open('subor2.txt', 'w').write('first line\nsecond line\nend of file\n')

Týmto jedným príkazom sme vytvorili nový súbor 'subor3.txt', zapísali sme do neho 3 riadky a automaticky sa na záver zatvoril (dúfajme…). Korektný zápis. ktorý by sme použili v programe:

with open('subor2.txt', 'w') as f:
    f.write('first line\nsecond line\nend of file\n')

Podobne by sme to zapísali aj pomocou príkazu print():

>>> print('first line\nsecond line\nend of file', file=open('subor3.txt', 'w'))

alebo radšej korektne:

with open('subor3.txt', 'w') as f:
    print('first line\nsecond line\nend of file', file=f)

Nezabudnite, že ak súbor 'subor3.txt' niečo pred tým obsahoval, týmto príkazom sa celý prepíše.

Vyššie uvedený príklad, ktorý kopíroval kompletný súbor:

t = open('subor.txt', 'r')
cely = t.read()
t.close()
t = open('subor2.txt', 'w')
t.write(cely)
t.close()

by sa dal úsporne zapísať takto:

>>> open('subor2.txt', 'w').write(open('subor.txt', 'r').read())

čo je zrejme veľmi ťažko čitateľné, a my to určite budeme zapisovať radšej takto korektne:

with open('subor.txt', 'r') as r:
    with open('subor2.txt', 'w') as w:
        w.write(r.read())

Niekedy to môžete vidieť aj v takomto tvare:

with open('subor.txt', 'r') as r, open('subor2.txt', 'w') as w:
    w.write(r.read())

To znamená, že do príkazu with môžeme zadať naraz viac otvorených súborov (oddelených čiarkou). Po skončení bloku príkazov sa všetky takto otvorené súbory automaticky zatvoria.

Hoci teraz už vieme zapísať príkaz, ktorý na konzolu vypíše obsah nejakého textového súboru takto:

>>> print(open('readme.txt').read())

budeme to zapisovať korektnejšie:

>>> with open('readme.txt') as t:
        print(t.read())

alebo

>>> with open('readme.txt') as t: print(t.read())

Všimnite si, že sme pri open() nepoužili parameter 'r' pre označenie otvorenia na čítanie. Keď totiž pri otváraní nezapíšeme 'r', Python si domyslí práve otváranie súboru na čítanie.

Ak očakávame, že otvorený súbor je príliš veľký a my ho naozaj nepotrebujeme vypísať celý, zapíšeme:

>>> with open('readme.txt') as t: print(t.read()[:1000])

Pridávanie riadkov do súboru

Videli sme dva rôzne typy otvárania textového súboru:

  • t = open('subor.txt', 'r') - súbor sa otvoril na len čítanie, ak ešte neexistoval, program spadne

  • t = open('subor.txt', 'w') - súbor sa otvoril na len zapisovanie, ak ešte neexistoval, tak sa vytvorí prázdny, inak sa zruší doterajší obsah (zapíše sa prázdny obsah)

Zoznámime sa s ešte jednou voľbou, pri ktorej sa súbor otvorí na zápis, ale nezruší sa jeho pôvodný obsah. Namiesto toho sa nové riadky budú pridávať na koniec súboru. Napr. ak máme súbor 'subor3.txt' s tromi riadkami:

first line
second line
end of file

môžeme do neho pripísať ďalšie riadky, napr. takto: namiesto 'r' a 'w' pri otváraní súboru použijeme 'a', ktoré označuje anglické append:

t = open('subor3.txt', 'a')
t.write('pridany riadok na koniec\na este jeden\n')
t.close()

v súbore je teraz:

first line
second line
end of file
pridany riadok na koniec
a este jeden

Zrejme by sme to zvládli naprogramovať aj bez tejto voľby, len pomocou pôvodného čítania a zápisu, ale bolo by to časovo náročnejšie riešenie, napr. takto:

with open('subor3.txt', 'r') as t:
    cely = t.read()                        # zapamätá si pôvodný obsah
with open('subor3.txt', 'w') as t:         # vymaže všetko
    t.write(cely)                          # vráti tam pôvodný obsah
    t.write('pridany riadok na koniec\na este jeden\n')

Zistite čo urobí:

for i in range(100):
    with open('subor4.txt', 'a') as file:
        print('vypisujem', i, 'riadok', file=file)

Uvedomte si, že takéto riešenie je veľmi neefektívne.

Príklad s grafikou

Máme pripravený textový súbor, v každom riadku ktorého sú dve celé čísla - súradnice nejakých bodov v grafickej ploche. Napr.

100 100
150 200
200 150
150 150

Napíšme program, ktorý prečíta súradnice týchto bodov a do grafickej plochy na príslušné miesta nakreslí malé krúžky:

import tkinter

canvas = tkinter.Canvas()
canvas.pack()
with open('body.txt') as subor:
    for riadok in subor:
        i = riadok.find(' ')
        x, y = int(riadok[:i]), int(riadok[i:])
        canvas.create_oval(x - 10, y - 10, x + 10, y + 10)
_images/07_01.png

Na cvičeniach budeme ďalej pracovať s touto ideou. Napr. budeme tieto body spájať úsečkami, alebo budeme generovať vlastné textové súbory s nejakými kresbami (postupnosťami bodov).



Cvičenia

L.I.S.T.

  1. V nejakom textovom editore vytvor textový súbor napr. s týmto obsahom:

    • text1.txt:

      Pocitac ma oproti ludskemu mozgu
      len jednu prednost
      - ze ho pouzivame.
      
      Gabriel Laub
      

    Napíš program, ktorý z tohto súboru vypíše druhý riadok

    • napr. pre súbor text1.txt:

      druhý riadok suboru: 'len jednu prednost'
      

  1. Napíš program, ktorý si vypýta meno súboru a potom vypíše každý druhý znak z prvého riadka tohto súboru.

    • napr. ak súbor 'text2.txt' obsahuje:

      Tri zakladne zakony robotiky.
      Po prve, robot nesmie zranit ludsku bytost alebo dovolit, aby sa jej v dosledku necinnosti ublizilo.
      Po druhe, robot musi posluchat prikazy ludskych bytosti, okrem pripadov, ked by taketo prikazy boli v rozpore s prvym zakonom.
      Po tretie, robot musi chranit svoju vlastnu existenciu, pokial takato ochrana nie je v rozpore s prvym a druhym zakonom
      
      Isaac Asimov
      
    • spustenie programu:

      zadaj meno súboru: text2.txt
      každý druhý znak: 'r aldezkn ooiy'
      
    • pre súbor z prvej úlohy:

      zadaj meno súboru: text1.txt
      každý druhý znak: 'oia aort useumzu'
      

  1. Napíš program, ktorý si vypýta meno súboru a potom vypíše počet riadkov a dĺžku najdlhšieho riadka (aj s koncovýn '\n').

    • napr. pre súbor 'text3.txt':

      Ján Botto
      Žltá ľalija
      
      Stojí stojí mohyla
      Na mohyle zlá chvíľa
      na mohyle tŕnie chrastie
      a v tom tŕní chrastí rastie
      rastie kvety rozvíja
      jedna žltá ľalija
       ľalija smutno vzdychá
      Hlávku moju tŕnie pichá
      a nožičky oheň páli
      pomôžte mi v mojom žiali
      
    • výpis môže vyzerať napr. takto:

      meno súboru: text3.txt
      počet riadkov súboru: 13
      najdlhší riadok  28 znakov
      
    • otestuj aj pre iné súbory, napr.

      meno súboru: text2.txt
      počet riadkov súboru: 6
      najdlhší riadok  127 znakov
      
    • zapíš tri rôzne riešenia tejto úlohy:

      1. čítaním pomocou readline() a while-cyklu

      2. čítaním riadkov pomocou for-cyklu

      3. prečítaním naraz celého súboru pomocou read()


  1. Napíš program, ktorý si vypýta meno súboru a potom vypíše všetky tie riadky súboru, ktoré obsahujú práve tri slová. V každom riadku je niekoľko slov, ktoré sú oddelené jednou medzerou.

    • výpis môže vyzerať napr. takto:

      meno súboru: text3.txt
      riadky s tromi slovami:
      Stojí stojí mohyla
      rastie kvety rozvíja
      jedna žltá ľalija
      
    • uvedom si, že stačí v každom riadku počítať počet medzier


  1. Napíš funkciu riadky_s_textom(meno_suboru, text), ktorá otvorí zadaný súbor (môže byť aj súbor s pythonovským programom) a vypíše z neho len tie riadky, ktoré obsahujú zadaný text.

    • napr.

      >>> riadky_s_textom('riesenie.py', 'if ')
      if a != b:
      elif b < 7:
          if x:
      
    • alebo

      >>> riadky_s_textom('text3.txt', 'ali')
      Žltá ľalija
      jedna žltá ľalija
      Tá ľalija smutno vzdychá
      pomôžte mi v mojom žiali
      

  1. Napíš a otestuj tieto funkcie. Ich parametrom je meno nejakého textového súboru a všetky vrátia (return) nejaký jeden riadok súboru:

    • funkcia posledny_riadok(meno_suboru)

    • funkcia predposledny_riadok(meno_suboru)

    • funkcia najdlhsi_riadok(meno_suboru)

    • napr.

      >>> posledny_riadok('text3.txt')
      'pomôžte mi v mojom žiali'
      >>> predposledny_riadok('text3.txt')
      'a nožičky oheň páli'
      >>> najdlhsi_riadok('text3.txt')
      'a v tom tŕní chrastí rastie'
      

  1. Napíš funkciu priemer(meno_suboru): funkcia číta súbor, v ktorom je v každom riadku jedno celé číslo, funkcia zistí priemer týchto hodnôt.

    • vytvorte napr. súbor 'cisla.txt':

      554
      -8
      27
      4448
      7
      92
      144
      
    • a otestujte:

      >>> print('priemer =', priemer('cisla.txt'))
      priemer = 752.0
      

  1. Vypíš obsah textového súboru do grafickej plochy. Súbor obsahuje niekoľko riadkov a funkcia vypis_subor(meno_suboru) tieto riadky vypíše pod sebou nejakým fontom. V globálnej premennej canvas je referencia na grafickú plochu.

    • napr.

      >>> vypis_subor('text3.txt')
      

      vypíše do grafickej plochy:

      _images/07_02.png
    • pre zarovnanie vypisovaného textu pomocou create_text nie na stred ale na ľavý okraj môžeš použiť ďalší pomenovaný parameter anchor='nw', potom by si mal dostať takýto výpis:

      _images/07_03.png

  1. Na prednáške bol program, ktorý z textového súboru čítal súradnice bodov x, y a do grafickej plochy na príslušných miestach kreslil malé krúžky. Zapíš to ako funkciu kresli(meno_suboru), ktorá namiesto kreslenia krúžkov, bude postupne spájať body zo súboru, t.j. najprv sa nakreslí úsečka z prvého bodu do druhého, potom z druhého do tretieho, …

    • napr. pre súbor 'body.txt' z prednášky:

      100 100
      150 200
      200 150
      150 150
      

      volanie:

      >>> kresli('body.txt')
      

      nakreslí tieto tri úsečky:

      _images/07_04.png
  2. Funkciu kresli() z predchádzajúceho príkladu vylepši takto: ak sa vo vstupnom súbore nachádza prázdny riadok, tento označuje, že za ním nasleduje ďalšia skupina bodov, ktorá ale nie je s predchádzajúcimi bodmi spojená.

    • napr. pre súbor 'body1.txt':

      100 100
      150 200
      200 150
      150 150
      
      220 50
      320 50
      320 150
      220 150
      220 50
      
      50 30
      150 70
      80 90
      50 30
      

      nakreslí:

      _images/07_05.png

  1. Textový súbor obsahuje v každom riadku jedno meno farby. Napíš funkciu do_riadkov(meno_suboru, sirka), ktorá vypíše rad štvorčekov (veľkosti 30x30). Každý z týchto štvorčekov zafarbí príslušnou farbou zo súboru. Po vykreslení sirka štvorčekov, pokračuje pod týmito v ďalšom rade štvorčekov s ďalšími farbami zo súboru. Takto pokračuje, kým sa neminú všetky farby zo súboru.

    • napr. pre súbor 'farby.txt':

      red
      blue
      red
      blue
      yellow
      red
      yellow
      red
      green
      yellow
      yellow
      green
      

      volanie

      import tkinter
      canvas = ...
      do_riadkov('farby.txt', 4)
      

      nakreslí:

      _images/07_06.png
    • ak by sme tento súbor vypisovali do 5 stĺpcov, dostali by sme:

      _images/07_07.png

  1. Napíš funkciu nahodne_cisla(meno_suboru, pocet). Funkcia vytvorí textový súbor s trojcifernými náhodnými číslami (zrejme z intervalu <100, 999>). V každom riadku bude jedno číslo, riadkov bude zadaný počet.

    • napr. volanie:

      >>> nahodne_cisla('cisla1.txt', 5)
      
    • vytvorí päťriadkový súbor 'cisla1.txt', ktorý môže obsahovať:

      272
      598
      822
      927
      233
      
    • otestujte takto vytvorený súbor s vašou funkciu, ktorá počíta priemer, napr.

      >>> nahodne_cisla('cisla2.txt', 100)
      >>> print('priemer =', priemer('cisla2.txt'))
      priemer = 540.58
      

  1. Napíš funkciu vyrob(meno_suboru, pocet, text), ktorá vytvorí textový súbor s daným menom. Tento súbor bude pythonovským skriptom, ktorý príslušný pocet krát vypíše (pomocou print()) zadaný text. Tento skript by mal na opakovanie výpisu využiť while-cyklus (nie for-cyklus).

    • napr.

      >>> vyrob('skript.py', 20, 'Programujem v Pythone')
      
    • vytvorí nový program 'skript.py' a ten po spustení, výpíše 20-krát pod seba:

      Programujem v Pythone
      Programujem v Pythone
      ...
      

  1. Napíš funkciu nahodne_body(meno_suboru, pocet), ktorá vygeneruje súbor s daným menom. Tento bude obsahovať zadaný pocet riadkov, pričom v každom bude náhodná dvojica celých čísel oddelená medzerou. Prvé číslo nach je z intervalu <10, 370> a druhé z intervalu <10, 250>.

    • takto vytvorený súbor by sa mohol využiť vo funkcii kresli z (10) úlohy, napr.

      >>> nahodne_body('body3.txt', 20)
      >>> kresli('body3.txt')
      
    • nakreslí a spojí nejakých 20 náhodných bodov, dostaneš niečo podobné:

      _images/07_08.png

  1. Napíš funkciu body_na_kruznici(meno_suboru, n, r, x, y), ktorá vygeneruje súbor s daným menom. Tento bude obsahovať n+1 riadkov, pričom v každom budú súradnice nejakého bodu ako dvojica celých čísel oddelená medzerou. Súbor bude obsahovať body pravideľného n-uholníka, ktoré sú rozložené na kružnici s polomerom r a so stredom v (x, y). Zrejme prvý a posledný (n+1) bod budú rovnaké, aby sa pri kreslení tento n-uholník uzavrel.

    • takto vytvorený súbor by sa mohol využiť vo funkcii kresli z (10) úlohy, napr.

      >>> body_na_kruznici('body4.txt', 20, 120, 250, 130)
      >>> kresli('body4.txt')
      
    • nakreslí takýto 20-uholník:

      _images/07_09.png
    • to isté pre trojuholník:

      _images/07_10.png