IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

1. diel - Výnimky

V tejto sekcii sa budeme venovať práci so súbormi. Než však môžeme začať zapisovať a čítať, mali by sme vyriešiť, ako ošetriť chybové stavy programu, ktorých pri práci so súbormi bude nastávať veľa.

V našom programe môže často dôjsť k chybe. Tým nemyslím chybe z dôvodu, že bol program funkčne zle napísaný, takýchto chýb sa sme schopní dobre vyvarovať. Všeobecne sa jedná najmä o chyby, ktoré zapríčinili tzv. Vstupno / výstupné operácie. V anglickej literatúre sa hovorí o input / output alebo skrátene o IO. Jedná sa napr. O vstup používateľa z konzoly, zo súboru, výstup do súboru, na tlačiareň a podobne. V zásade platí, že tu figuruje užívateľ, ktorý nám môže zadať nezmyselný vstup, neexistujúce alebo nevalidný súbor, odpojiť tlačiareň a podobne. My však nenecháme program spadnúť s chybou, naopak budeme zraniteľné miesta v programe ošetrovať a na danú skutočnosť užívateľa upozorníme.

Aktívny ošetrenie chýb

Prvá možnosť ošetrenia chýb nazývame ako aktívny. V programe nájdeme všetky zraniteľné miesta a ošetríme je podmienkami. Ako učebnicový príklad sa spravidla používa delenie nulou. Predstavme si program, ktorý používa triedu Matematika, ktorá má metódu Podiel. Trieda by mohla vyzerať napr. Nasledovne:

Class Matematika
    Public Shared Function Podil(a As Integer, b As Integer)
        Return a / b
    End Function
    ...
End Class

Teraz triedu použijeme takýmto spôsobom:

Console.WriteLine("Zadejte dělitele a dělence k výpočtu podílu:")
Dim a As Integer = Console.ReadLine()
Dim b As Integer = Console.ReadLine()
Console.WriteLine(Matematika.Podil(a, b))

Ak teraz programu užívateľ zadá čísla 12 a 0, program spadne s chybou, pretože nulou nemožno deliť. Aktívne chybu ošetríme jednoduchú podmienkou v programe:

Console.WriteLine("Zadejte dělitele a dělence k výpočtu podílu:")
Dim a As Integer = Console.ReadLine()
Dim b As Integer = Console.ReadLine()
If b <> 0 Then
    Console.WriteLine(Matematika.Podil(a, b))
Else
    Console.WriteLine("Nulou nelze dělit.")
End If

Teraz si musíme pri každom použití metódy teda strážiť, či do druhého parametru nevkladáme nulu. Predstavte si, že by metóda brala parametrov 10 a používali sme ju v programe niekoľkokrát. Určite je veľmi zložité takto ošetrovať všetky vstupy vo všetkých prípadoch.

Riešením by mohlo byť vložiť kontrolu priamo do metódy. Máme tu však nový problém: Akú hodnotu vrátime, keď bude 2. parameter nulový? Potrebujeme hodnotu, z ktorej spoznáme, že výpočet neprebehol korektne. To je však problém, keď zvolíme napr. Nulu, nespoznáme, či 0/12 je chybný výpočet alebo nie. Nevieme, či 0 značí výsledok alebo chybu. Ani zápornými číslami si nepomôžeme. V .NET je podobná metóda TryParse, ktorá vracia Boolean a hodnota sa odovzdáva cez modifikovaný parameter. To je však neprehľadné. Parsovanie hodnôt je 2. klasický príklad zraniteľného vstupu od užívateľa. Ďalšie sú súborové operácie, kde súbor nemusí existovať, nemusíme naň mať práva, môže s ním byť práve pracované a podobne.

Pasívne ošetrenie chýb

Keď je operácia zložitejšie a bolo by príliš náročné ošetrovať všetky možné chybové stavy, nastupujú výnimky, tzv. Pasívne ošetrenie chýb. Nás totiž vôbec nemusí zaujímať vnútorná logika v metóde, ktorú voláme. Pokúsime sa nebezpečnú časť kódu spustiť v "chránenom režime". Tento režim je nepatrne pomalšie a líšia sa tým, že ak dôjde k chybe, máme možnosť ju odchytiť a zabrániť pádu programu. O chybe tu hovoríme ako o výnimke. Využívame k tomu tzv. Try-catch bloky:

Try

Catch ex As Exception

End Try

Do bloku try umiestnime nebezpečnú časť kódu. Ak nastane v bloku try chyba, jeho vykonávanie sa preruší a program prejde do bloku catch. Ak všetko prebehne v poriadku, try sa vykoná celý a catch sa preskočí. Vyskúšajme si situáciu na našom predchádzajúcom príklade:

Try
    Console.WriteLine(Matematika.Podil(a, b))
Catch ex As Exception
    Console.WriteLine("Při dělení nastala chyba.")
End Try

Kód je jednoduchšie v tom, že nemusíme ošetrovať všetky zraniteľné miesta a premýšľať, čo všetko by sa mohlo pokaziť. Nebezpečný kód iba obalíme blokom Try a všetky chyby sa zachytí v Catch. Samozrejme do try-catch bloku umiestnime len to nevyhnutne potrebné, nie celý program :)

Teraz teda už vieme, ako ošetriť situácie, kedy užívateľ zadáva nejaký vstup, ktorý by mohol vyvolať chybu. Nemusí sa jednať len o súborové operácie, výnimky majú veľmi širokú oblasť použitia. Ostatne napr. Metóda Integer.TryParse, ktorú dobre poznáme a ktorú sme na ošetrenie vstupov používali, v sebe interne blok try-catch obsahuje. Dokážeme náš program napísať tak, aby sa nedal jednoducho užívateľom zhodiť.

Použitie výnimiek pri práci so súbormi

Ako už bolo povedané, súborové operácie môžu vyvolať mnoho výnimiek, preto sa súbory vždy pracujeme v try-catch bloku. Existuje aj niekoľko ďalších konštrukcií, ktoré pri výnimkách môžeme využívať.

Finally

Do try-catch bloku môžeme pridať ešte 3. blok a to Finally. Ten sa spustí vždy nech k výnimke došlo alebo nie. Predstavte si nasledujúcu metódu pre uloženie nastavení. Metódy pre obsluhu súboru budú vymyslené:

Public Sub UlozNastaveni()
    Try
        OtevriSoubor("soubor.dat")
        ZapisDoSouboru(nastaveni)
    Catch
        Console.WriteLine("Chyba při zápisu do souboru.")
    End Try
    If SouborJeOtevreny() Then
        ZavriSoubor()
    End If
End Sub

Metóda sa súbor pokúsi otvoriť a zapísať do neho objekt nastavení. Pri chybe vypíše hlášku do konzoly. Otvorený súbor musíme opäť uzavrieť. Vypisovať chyby priamo v metóde je však škaredé, to napokon už vieme, metódy a objekty vo všeobecnosti by mali vykonávať len logiku a komunikáciu s užívateľom obstaráva ten, kto je volá. Dajme teda metóde návratovú hodnotu Boolean a vracajte true / false podľa toho, či sa operácia podarila alebo nie:

Public Function UlozNastaveni() As Boolean
    Try
        OtevriSoubor()
        ZapisDoSouboru()
        Return True
    Catch
        Return False
    End Try
    If SouborJeOtevreny() Then
        ZavriSoubor()
    End If
End Function

Na prvý pohľad to vyzerá, že sa súbor vždy uzavrie. Celý kód je však v nejakej metóde, v ktorej voláme return. Ako vieme, return ukončí metódu a nič za ním sa už nevykoná.

Súbor by tu vždy zostal otvorený a uzavretie by sa už nevykonalo. Ako následok by to mohlo mať, že by bol potom súbor neprístupný. Ak vložíme zatvorenie súboru do bloku Finally, vykoná sa vždy. VB.NET si pamätá, že blok try-catch obsahoval Finally a po opustení sekcie Catch zavolá Finally:

Public Function UlozNastaveni() As Boolean
    Try
        OtevriSoubor()
        ZapisDoSouboru()
        Return True
    Catch
        Return False
    Finally
        If SouborJeOtevreny() Then
            ZavriSoubor()
        End If
    End Try
End Function

Finally sa teda používa u výnimiek na upratovacie práce, dochádza tu k zatváranie súborov, uvoľňovanie pamäte a podobne.

Celú situáciu som teraz značne zjednodušil. Pre každý typ súborov poskytuje VB.NET triedu zapisovača a čítacie (writer a reader). Metóda pre uloženie napr. Nastavenie by vo VB.NET reálne vyzerala asi takto:

Public Function UlozNastaveni() As Boolean
    Dim z As ZapisovacSouboru = Nothing
    Try
        z = New ZapisovacSouboru("soubor.dat")
        z.Zapis(objekt)
        Return True
    Catch
        Return False
    Finally
        If z IsNot Nothing Then
            z.Zavri()
        End If
    End Try
End Function

Takto sa naozaj reálne so súbormi pracuje, iba triedu som si vymyslel. Do inštancie zapisovača umiestnime najprv Nothing. Potom, už v bloku Try, skúsime vytvoriť zapisovač na súbore soubor.dat a zapísať nejaký objekt. Ak sa všetko podarí, vrátime True (samozrejme sa potom ešte zavolá blok Finally). Operácia môže zlyhať z dvoch dôvodov. Buď sa do súboru nepodarí zapísať alebo sa nám súbor pre zápis ani nepodarí otvoriť. Výnimku v každom prípade zachytíme a vrátime False, z čoho sa potom spozná, že sa metóde uloženie nepodarilo. Blok Finally zavrie súbor, ktorý zapisovač otvoril. Keďže sa ale otvorenie nemuselo podariť, musíme sa najprv pozrieť, či sa zapisovač vôbec vytvoril, aby sme mali čo zatvárať. Metódu by sme volali napr. Nasledovne:

If Not UlozNastaveni() Then
    Console.WriteLine("Nepodařilo se uložit nastavení.")
End If

Blok Catch môžeme vynechať a nechať metódu, aby výnimku pokojne vyvolala. Budeme počítať s tým, že sa s výnimkou vysporiada ten, kto metódu zavolal, nie metóda sama. Je to tak lepšie, ušetríme návratovú hodnotu metódy (ktorú možno potom použiť na niečo iné) a kód sa nám zjednoduší:

Public Sub UlozNastaveni()
    Dim z As ZapisovacSouboru = Nothing
    Try
        z = New ZapisovacSouboru("soubor.dat")
        z.Zapis(objekt)
    Finally
        If z IsNot Nothing Then
            z.Zavri()
        End If
    End Try
End Sub

Metódu by sme teraz volali nasledovne:

Try
    UlozNastaveni()
Catch
    Console.WriteLine("Nepodařilo se uložit nastavení.")
End Try

Teraz si ukážeme, ako celú situáciu ešte viac zjednodušiť. Použijeme konštrukciu Using.

Using

Visual Basic .NET umožňuje značne zjednodušiť prácu s inštanciami tried na čítanie a zápis do súborov. Vyššie uvedený blok môžeme zapísať pomocou notácie Using, ktorá nahrádza bloky Try a Finally. Obrovskou výhodou je, že blok Finally VB.NET vygeneruje sám a sám zabezpečí, aby daná inštancia readeru alebo writerov súbor uzavrela. Metóda UlozNastaveni () by teda vyzerala s pomocou Using takto:

Public Sub UlozNastaveni()
    Using z As New ZapisovacSouboru("soubor.dat")
        z.Zapis(objekt)
    End Using
End Sub

Vidíme, že sa kód extrémne zjednodušil, aj keď robí v podstate to isté. Pri volaní metódy opäť použijeme try-catch blok. Nezabudnite, že Using nahrádza iba try-finally, nie Catch!. Metódu, v ktorej sa používa v Using, musíme rovnako volať v try-catch bloku.

Teraz sme dospeli presne tam, kam som chcel. K všetkým manipuláciám so súbormi totiž budeme v nasledujúcich tutoriáloch používať konštrukciu Using. Kód bude jednoduchšie a nikdy sa nám nestane, že by sme súbor zabudli zavrieť.

K výnimkám sa ešte raz vrátime, ukážeme si, ako odchytávať len niektoré typy výnimiek, ktoré hotové triedy výnimiek môžeme v našich programoch používať a tiež, ako vytvoriť výnimku vlastné. Teraz som však chcel vysvetliť len potrebné minimum pre prácu so súbormi a nie vám zbytočne pliesť hlavu zložitými konštrukciami :)

Nabudúce, Úvod do práce so súbormi , sa pozrieme, ako to funguje s právami na zápis do súborov v systéme Windows a vyskúšame si niekoľko prvých súborových operácií.


 

Všetky články v sekcii
Súbory a sieť vo Visual Basic .NET
Preskočiť článok
(neodporúčame)
Úvod do práce so súbormi
Článok pre vás napísal Michal Žůrek - misaz
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.
Aktivity