Letní akce PHP týden
Pouze tento týden sleva až 80 % na kurzy PHP. Lze kombinovat s akcí Letní slevy na prémiový obsah!
Brno? Vypsali jsme pro vás nové termíny školení Základů programování a OOP v Brně!

Lekce 3 - Práce s textovými soubory v C#

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Úvod do práce se soubory, jsme si ukázali, jak fungují přístupová práva v systémech Windows. Nejjednodušší cestou, jak uložit data aplikace na pevný disk, je využít textové soubory. Se soubory s příponou .txt jste se jistě všichni již setkali. Text je v nich uložen jednoduše na jednotlivých řádcích. K oddělení řádků se využívá speciálních znaků, které jsou bohužel specifické pro každý operační systém. Toto však za nás naštěstí vyřeší C#.

Pozn.: V různých materiálech se můžete setkat s použitím různých tříd a různých způsobů k zápisu do souborů. .NET framework se v čase vyvíjel a pro některé funkčnosti poskytuje kvůli kompatibilitě i starší nebo komplikovanější konstrukce. Budu se zde snažit ukazovat způsoby, které jsou nejjednodušší a nejnovější.

Zápis textu do nového souboru

Nejprve si pojďme vytvořit nový textový soubor a něco do něj zapsat. Vytvořte si nový projekt (konzolovou aplikaci) s názvem TextoveSoubory. K zapisování do textových souborů nám .NET poskytuje třídu StreamWriter.

Ve zdrojovém kódu si nejprve do using přidejme System.IO. Nyní vytvořme blok using a založme v něm novou instanci StreamWriter. Jak již víme z předchozích lekcí, using se nám automaticky postará o zavření souboru po dokončení zápisu/čtení. Do konstruktoru napíšeme cestu k našemu souboru.

using (StreamWriter sw = new StreamWriter(@"soubor.txt"))
{
}

Náš StreamWriter je nyní nasměrovaný na správný soubor. Nový řádek zapíšeme pomocí metody WriteLine(). Po dokončení zápisu musíme zavolat metodu Flush(), která se stará o vyprázdnění bufferu. S tím se zde nebudeme zatěžovat, postačí nám vědět, že námi zapsané řádky mohou zůstat chvíli ve vyrovnávací paměti a my pomocí Flush() vynutíme jejich zápis.

Kód se nám tedy rozrostl a může vypadat např. takto:

using (StreamWriter sw = new StreamWriter(@"soubor.txt"))
{
    sw.WriteLine("První řádek");
    sw.WriteLine("Tento text je na druhém řádku");
    sw.WriteLine("A do třetice.");
    sw.Flush();
}

Po spuštění se vytvoří soubor.txt ve složce s naším projektem, přesněji v bin/debug/. Jak se správně v C# vypořádat s cestou k souboru a právy jsme si již ukazovali a zde to pro jednoduchost zanedbáme. Vidíme, že soubor existuje a opravdu obsahuje náš text:

Zápis textových souborů v C# .NET

Připsání textu do existujícího souboru

Pokud soubor neexistuje, kód výše ho vytvoří. Pokud existuje, bude přepsán. Toto chování můžeme změnit pomocí 2. parametru konstruktoru objektu StreamWriter. Pokud ho nastavíme na true, provede se tzv. append (připsání). Takto do existujícího souboru připíšeme nový řádek:

using (StreamWriter sw = new StreamWriter(@"soubor.txt", true))
{
    sw.WriteLine("Připsaný řádek");
    sw.Flush();
}

Dalším parametrem může být nastavení kódování, ale výchozí UTF-8 by nám mělo ve většině případů vyhovovat.

Čtení existujícího souboru

Zbývá nám již jen umět soubor načíst. Není to o nic složitější, než zápis a opět k tomu máme v .NET frameworku připravenou třídu, konkrétně StreamReader. Použití je obdobné, namísto metody WriteLine() použijeme ReadLine(), která vrací řádek textu ze souboru a zároveň se přesune na řádek následující. Budeme ji tedy volat ve while cyklu. Podmínka pro ošetření vyjetí ze souboru je možná krkolomnější, kontrolujeme, zda proběhlo přiřazení nové řádky do proměnné.

Kód k výpisu obsahu souboru do konzole by vypadal takto:

using (StreamReader sr = new StreamReader(@"soubor.txt"))
{
    string s;
    while ((s = sr.ReadLine()) != null)
    {
        Console.WriteLine(s);
    }
}

Kód celého našeho programu vypadá nyní asi takto:

// zápis do souboru
using (StreamWriter sw = new StreamWriter(@"soubor.txt"))
{
    sw.WriteLine("První řádek");
    sw.WriteLine("Tento text je na druhém řádku");
    sw.WriteLine("A do třetice.");
    sw.Flush();
}
Console.WriteLine("Do souboru bylo zapsáno.");

// připsání textu do existujícího souboru
using (StreamWriter sw = new StreamWriter(@"soubor.txt", true))
{
    sw.WriteLine("Připsaný řádek");
    sw.Flush();
}
Console.WriteLine("Do souboru bylo připsáno.");

// výpis obsahu souboru
Console.WriteLine("Vypisuji soubor:");

using (StreamReader sr = new StreamReader(@"soubor.txt"))
{
    string s;
    while ((s = sr.ReadLine()) != null)
    {
        Console.WriteLine(s);
    }
}
Console.ReadKey();

A výsledek:

Zápis a čtení textových souborů v C# .NET

Třída File

.NET framework v sobě obsahuje statickou třídu File s předpřipravenými metodami, které práci se StreamReaderem/StreamWriterem sice plně nenahradí, ale ve velkém množství případů si s nimi vystačíme. Poslední příklad vypisující všechny řádky ze souboru by se dal zapsat takto (nezapomeňte na using System.IO):

string[] radky = File.ReadAllLines(@"soubor.txt");
foreach (string radka in radky)
{
    Console.WriteLine(radka);
}

Metoda ReadAllLines() nám vrátí všechny řádky textového souboru v poli stringů. Pokud se nejedná o nějaký velký soubor, je tato metoda mnohem jednodušší na použití. Na třídě File naleznete i další podobné metody jako WriteAllLines(poleStringu, cestaKSouboru) nebo AppendAllLines(poleStringu, cestaKSouboru). První zmíněná zapíše do souboru řádky z pole stringů, druhá připíše k existujícímu souboru řádky z pole stringů. Třída obsahuje také ekvivalenty metod, které nepracují s řádkami, ale souvislým textem. Jsou to WriteAllText(text), ReadAllText() a AppendAllText(text).

V článku jsme opomenuli odchytávání výjimek a kontrolu práv. Do souborů také budeme chtít většinou ukládat spíše objekty, než řádky textu. To vše si ukážeme v příští lekci, Uložení objektů do CSV v C#.


 

Stáhnout

Staženo 1096x (24.76 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
18 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Předchozí článek
Úvod do práce se soubory
Všechny články v sekci
Práce se soubory v C#
Miniatura
Následující článek
Uložení objektů do CSV v C#
Aktivity (5)

 

 

Komentáře
Zobrazit starší komentáře (52)

Avatar
Patrik Pastor:2. května 22:31

Chtel jsem se zeptat, sice to "pro jednoduchost" autor neuvadi, ale chtel jsem si zapis do souboru vyzkouset ve vytvorenem souboru ve druhe dile (kde je rec o pravech a kod s try, catch podminkama), ale soubor se mi nevypsal, takze by bylo dobre pro tu "jednoduchost" udelat i priklad. Udelal jsem toto:

if (File.Exists(Pat­h.Combine(ces­ta, "databaze.dat")))
{
try
{
// Zde umístěte kód pro načtení vašeho nastavení ze souboru
....
}
catch
{
...
}
else
{
try
{
// Zde umístěte kód pro vytvoření vašeho nastavení
using (StreamWriter sw = new StreamWriter(@"C:\U­sers\ppast\Ap­pData\Roaming\A­plikace"))
// cesta k prvnimu vytvorenemu souboru se vsemi podminkami a pravy
{
sw.WriteLine("První řádek");
sw.WriteLine("Tento text je na druhém řádku");
sw.WriteLine("A do třetice.");
sw.Flush();
}
}

Ale nevypsalo se mi nic (reps. nevytvoril se ani soubor), takze prosim o radu, nebo autora aby si dal praci a pro tu "jednoduchost" udelal priklad se souborem i se pravy a podminkami, diky

 
Odpovědět 2. května 22:31
Avatar
Michal Žůrek - misaz:3. května 0:09

Jedná se o to že při I/O operacích se volají funkce operačního systému a po dokončení práce se opět musí volat funkce operačního systému na uzavření souboru. Toto ale GC nedělá, potože to ani není jeho práce. GC čistí paměť, neprovádí volání operačního systému.

Volání Close, respktive Dispose naopak ten objekt neodstraní z paměti, ale pouze provede to volání operačního systému, které v operačním systému uzavře přístup k souboru. O odstranění objektu (např. StreamWriter) z paměti se potom řádně postará GC.

Pokud Close nezavoláš, tak GC ten objekt odstraní z paměti (ale nezavolá funkci zavření v operačním systému). Paměťově je to v tvé aplikaci OK, ale v operačním sytému stále visí ten otevřený soubor se kterým jednak nejde pracovat (ani tvoje aplikace, která už nemá třídu, která se souborem uměla pracovat, ani jiné aplikace, protože soubor je blokován tvou aplikací) a jednak operační systém musí kvůli toho udržovat nějaké interní informace, které zabírají paměť (a toto teprve dělá ten memory leak).

Editováno 3. května 0:10
 
Odpovědět 3. května 0:09
Avatar
Michal Žůrek - misaz:3. května 0:12

Destruktory se v .NET moc nepoužívají, protože to zpomaluje čištění paměti a přidává overhead každému objektu. Místo toho se používá using blok a rozhraní IDisposable, které ten overhead přidává jen třídám, které to opravdu potřebují.

 
Odpovědět 3. května 0:12
Avatar
Odpovídá na Patrik Pastor
Michal Žůrek - misaz:3. května 0:14

takt o spadlo na nějakou vyjímku. Zakomentuj si blok try/catch nebo si dej do catch breakpoint nebo něco a uvidíš.

 
Odpovědět 3. května 0:14
Avatar
Odpovídá na Michal Žůrek - misaz
Patrik Pastor:3. května 8:19

Takze kod je ok? Muzu pouzivat using v tom kontextu?(tedy v podmince else, kdyz jeste neexistuje soubor, a je using pouzit v try bloku). Cili kod je ok, ale mam hledat exception, kterou to vyhodi?

 
Odpovědět 3. května 8:19
Avatar
Odpovídá na Michal Žůrek - misaz
Patrik Pastor:3. května 8:22

pokud by ale byly destruktory zde, tak by prece zrusili referencen jak v aplikaci, tak v operacni pameti (timpadem by nedochazovalo k memoryleak) a GC by byl zbytecny, proc se tedy nepouzivaji?

 
Odpovědět 3. května 8:22
Avatar
Odpovídá na Patrik Pastor
Michal Žůrek - misaz:3. května 13:19

using můžeš (a měl bys) používat všude, kde pracuješ v souboru. Je jendo jestli je to v else, try nebo někde jinde.

 
Odpovědět 3. května 13:19
Avatar
Odpovídá na Patrik Pastor
Michal Žůrek - misaz:3. května 13:20

viz. můj 2 komentář z 3.5.2019 0:12

Destruktory se v .NET moc nepoužívají, protože to zpomaluje čištění paměti a přidává overhead každému objektu. Místo toho se používá using blok a rozhraní IDisposable, které ten overhead přidává jen třídám, které to opravdu potřebují.

 
Odpovědět 3. května 13:20
Avatar
Patrik Pastor:3. května 15:43

chtel bych se zeptat, z dalsi lekce, kde zapisujeme do textaku pomoci StreamWriter, jsem chtel neco napsat do souboru. Kdyz jsem zapisoval cestu do new StreamWriter(ces­ta), vyhodilo mi to chybu. Cesta je ale spravne a smeruje do meho vytvoreneho souboru z tohoto dilu. Musel jsem tedy prepsat na Path.Combine(cesta, "neco.txt"), aby se mi to tam konecne ulozilo. Ptam se tedy proc se mi to defaulne neuklada do souboru, kdery jsem vytvoril (respektive slozku), ale musil pro dalsi soubory vytvaret nove. Diky za odpoved

 
Odpovědět 3. května 15:43
Avatar
Odpovídá na Michal Žůrek - misaz
Patrik Pastor:3. května 19:03

jak se potom lisi ty tridy, ktere ten "overhead" potrebuji od tech, ktere ne? Napsat to, bez dalsich detailu neni zcela dostacujici, proc by se potom destruktory pouzivaly v nizsich jazicich (ktere jsou prave rychlejsi a destruktor maji, takze by to bylo opak k tomu, co tvrdis).

 
Odpovědět 3. května 19:03
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 62. Zobrazit vše