Jedním z námětů, které jsem obdržel v rámci své výzvy ptejte se mne na co chcete, já na co chci odpovím, byla žádost o vysvětlení práce s textovými soubory. Zadání jsem si rozšířil na práci s obsahem souborů obecně - nebo chcete-li se streamy.

Co je stream

Většina vstupně/výstupních operací se v .NET děje prostřednictvím nějaké formy streamu. Stream představuje obecně jakýkoliv objekt, ze kterého lze číst nebo do něj zapisovat bajty. Tato abstrakce je velmi široce použitelná: v tomto článku se budu zabývat toliko soubory, ale tentýž přístup je možno aplikovat na TCP/IP síťové spojení, komunikaci přes sériový port, kryptografické operace a řadu dalších věcí.

Základní třídou je v tomto případě System.IO.Stream. Jeho základní metody jsou ReadByte, Read, WriteByte a Write. Ty umožňují přečíst nebo zapsat jeden či více bajtů. Steam může umožňovat čtení, zápis nebo obojí. To lze zjistit z vlastností CanRead a CanWrite. Metodou Close lze stream zavřít (a v případě souborů zapsat provedené změny na disk).

Tato třída je abstraktní a musí být tedy v praxi implementována pomocí specializovaných tříd jako je například FileStream, NetworkStream nebo MemoryStream.

Textové soubory

Možnosti samotného streamu nejsou moc velké. Zapsat nebo přečíst hromádku bajtů sice v zásadě stačí, ale pro praktickou práci by bylo potřeba napsat spoustu věcí okolo. Pro práci s textovými soubory proto .NET obsahuje třídy System.IO.StreamReader a System.IO.StreamWriter. Ty umožňují pohodlně ze streamu číst nebo do něj zapisovat řetězcová data v požadovaném kódování. Disponují přitom metodami jako ReadLine nebo WriteLine, které umožňují zpracování souboru po řádcích.

Následující kód tedy vytvoří textový soubor a zapíše do něj dva řádky textu:

Dim Soubor As New System.IO.StreamWriter(Server.MapPath("/StreamDemo/demo.txt"))
Soubor.WriteLine("První řádek")
Soubor.WriteLine("Druhý řádek")
Soubor.Close()

Vcelku podobným způsobem je možno soubor i číst. Zde se uplatní též metoda Peek. Ta "nakoukne" na další bajt v souboru a aniž by posunula pomyslný kurzor, vrátí jeho hodnotu. V případě, že narazí na konec souboru, vrátí -1. Toho lze s úspěchem využít při řešení úloh typu "načítej dokud nenarazíš na konec souboru. Následující kód přečte po řádcích obsah zdrojového souboru a vypíše ho na výstup:

Dim Soubor As New System.IO.StreamReader(Server.MapPath("/StreamDemo/demo.txt"))
Do While Soubor.Peek() > -1
    Dim Radek As String = Soubor.ReadLine()
    Response.Write(Radek & "<br>")
Loop
Soubor.Close()

V tomto konkrétním případě je víceméně zbytečné číst soubor po řádcích. Mnohem jednodušší by bylo použít metodu ReadToEnd a poté prostě nahradit konce řádků tagem <br>.

Různá kódování

.NET Framework vnitřně pracuje se všemi daty v kódování UNICODE, resp. UTF-8. I jeho výše uvedené třídy tedy implicitně předpokládají, že veškerá data jsou k dispozici v UTF-8. Ačkoliv vám vřele doporučuji, aby vaše programy tuto logiku přejaly (ušetříte si tím spoustu práce a problémů), může se stát, že data dostanete v kódování jiném.

Ani to nepředstavuje zásadní problém. Obšírnější pojednání o kódování řetězců v .NET jsem napsal již před časem, detaily si přečtěte v něm. Pro účely čtení nebo zápisu pomocí StreamReaderu a StreamWriteru stačí prostě požadované kódování specifikovat jako další volitelný parametr. Máte-li tedy vstupní data například v kódování Windows 1250, stačí příslušný řádek modifikovat takto:

Dim Soubor As New System.IO.StreamReader(Server.MapPath("/StreamDemo/demo.txt"), _
                  System.Text.Encoding.GetEncoding("Windows-1250"))

Pohodlný přístup

V příkladech výše jsem soubory volal přímo pomocí odpovídajícího StreamReaderu či StreamWriteru. Zcela stejných výsledků, někdy pohodlnější cestou, lze dosíci použitím rozličných statických metod v System.IO.File. Například CreateText, AppendText a OpenText.