4. díl - Uložení objektů do CSV v C#

C# .NET Práce se soubory Uložení objektů do CSV v C#

V minulém dílu seriálu tutoriálů o C# jsme si ukázali zápis do textových souborů i jejich čtení. Aplikace byla jednoduchá a spíše učebnicová. Udělejme si nyní opravdovou databázi uživatelů pomocí textových souborů. Ukládat budeme samozřejmě objekty, čili si program snadno předěláte na databázi upomínek v diáři, databázi nejlepších výsledků ve hře, databázi zvířat v chovné stanici a tak podobně.

Formát CSV

Nebudeme vymýšlet žádný složitý způsob ukládání dat do textových souborů, protože již jeden osvědčený a standardní existuje. Jmenuje se CSV (jako Comma Separated Values), tedy hodnoty oddělené čárkou, případně středníkem. O CSV jsme se zmínili v článku o metodách Split a Join na řetězci , dnes je tedy budeme potřebovat.

Pojďme se shodnout na tom, jak bude třída uživatele vypadat. Následně si ukážeme, jak její instance do CSV uložíme. Založte si nový projekt typu Windows Forms Application. Přidáme si k němu třídu Uzivatel. U uživatele budeme evidovat jeho jméno, věk a datum, kdy byl registrován. Konstruktor bude instanci tvořit na základě těchto 3 údajů. Přetížíme si metodu ToString tak, aby vypsala jméno uživatele. Třída tedy bude vypadat takto:

class Uzivatel
{
        public string Jmeno { get ; private set; }
        public int Vek { get; private set; }
        public DateTime Registrovan { get; private set; }

        public Uzivatel(string jmeno, int vek, DateTime registrovan)
        {
                Jmeno = jmeno;
                Vek = vek;
                Registrovan = registrovan;
        }

        public override string ToString()
        {
                return Jmeno;
        }

}

Pojďme si ukázat, jak budou uživatelé ve formátu CSV vypadat. Každý řádek bude reprezentovat jednoho uživatele. Vlastnosti uživatele budou odděleny středníky. Uživatel Pavel Slavík, kterému je 22 let a zaregistroval se 21.3.2000 by vypadal takto:

Pavel Slavík;22;21.3.2000

Na první pohled vidíme, že je soubor relativně jednoduše čitelný i když nezasvěcený se může jen domnívat, co je číslo 22 a k čemu se váže ono datum.

V souboru může být samozřejmě více uživatelů, tedy více řádků.

Třídu uživatele máme, protože však ctíme objektový návrh, vytvoříme si i třídu pro naši databázi. Ta bude obsahovat kolekci uživatelů, tvořenou instancí třídy List. Kolekce bude privátní a přidávání uživatelů (případně jejich mazání, vyhledávání a podobně) bude realizováno veřejnou metodou. Databáze bude konečně obsahovat metody k načtení CSV souboru a také k uložení obsahu databáze do souboru. Jméno souboru bude další privátní proměnná databáze. Přidejme si tedy k projektu další třídu Databaze a napišme její kostru:

class Databaze
{
        private List<Uzivatel> uzivatele;
        private string soubor;

        public Databaze(string soubor)
        {
        }

        public void PridejUzivatele(string jmeno, int vek, DateTime registrovan)
        {
        }

        public Uzivatel[] VratVsechny()
        {
        }

        public void Uloz()
        {
        }

        public void Nacti()
        {
        }
}

VS nám metodu VratVsechny podtrhne červeně (protože nevrací hodnotu), ale toho si zatím nebudeme všímat. Pojďme postupně naimplementovat jednotlivé metody. Začněme konstruktorem.

V konstruktoru vytvoříme instanci Listu a uložíme si cestu k databázovému souboru:

public Databaze(string soubor)
{
        uzivatele = new List<Uzivatel>();
        this.soubor = soubor;
}

To bylo velmi jednoduché a i na další metodě není co vymýšlet:

public void PridejUzivatele(string jmeno, int vek, DateTime registrovan)
{
        Uzivatel u = new Uzivatel(jmeno, vek, registrovan);
        uzivatele.Add(u);
}

Metoda VratVsechny() nám vrátí všechny uživatele. Podobně můžeme v budoucnu udělat metody pro vyhledávání jen některých uživatelů. Uživatele navrátíme ve formě pole.

public Uzivatel[] VratVsechny()
{
        return uzivatele.ToArray();
}

Uložení uživatelů do CSV

Nyní se konečně dostáváme k práci s CSV souborem. Začneme using blokem s instancí StreamWriteru. Uvnitř proiterujeme náš list uživatelů a pro každého uživatele vytvoříme pole stringů z jeho vlastností. Nestringové vlastnosti musíme na string explicitně převést. Pole poté spojíme na dlouhý string, ve kterém budou položky oddělené středníky. Spojení za nás vykoná metoda Join. Ta se narozdíl od metody Split volá přímo na třídě String a jako parametr (spojovací text) bere také string, nikoli char. Pusťme se do toho:

public void Uloz()
{
        // otevření souboru pro zápis
        using (StreamWriter sw = new StreamWriter(@"soubor.txt"))
        {
                // projetí uživatelů
                foreach (Uzivatel u in uzivatele)
                {
                        // vytvoření pole hodnot
                        string[] hodnoty = { u.Jmeno, u.Vek.ToString(), u.Registrovan.ToShortDateString() };
                        // vytvoření řádku
                        string radek = String.Join(";", hodnoty);
                        // zápis řádku
                        sw.WriteLine(radek);
                }
                // vyprázdnění bufferu
                sw.Flush();
        }
}

Kdybychom u data registrace ponechali jen ToString(), uložil by se nám i čas, což zde není příhodné. Pojďme si vše vyzkoušet, přejděme k souboru Formuláře (Form1.cs, případně v designeru F7). Zavedeme privátní proměnnou databaze, do které v konstruktoru formuláře vytvoříme instanci naší databáze:

private Databaze databaze;

public Form1()
{
        InitializeComponent();
        databaze = new Databaze("uzivatele.csv");
}

Na formulář přidejme nové tlačítko, pojmenujme ho tlacitkoUlozit a Text mu nastavme na Uložit.

Formulář pro uložení do CSV v C#

V jeho Click handleru (vytvoří se po dvojkliku na tlačítko) přidáme do databáze 2 uživatele. Bude to nyní pro vyzkoušení, později bude aplikace vypadat lépe. Dále celou databázi uložíme do souboru.

private void tlacitkoUlozit_Click(object sender, EventArgs e)
{
        databaze.PridejUzivatele("Pavel Slavík", 22, new DateTime(2000, 3, 21));
        databaze.PridejUzivatele("Jan Novák", 31, new DateTime(2012, 10, 30));
        databaze.Uloz();
}

Aplikaci spustíme a klikneme na tlačítko. Nyní otevřeme (např. v NotePadu) soubor uzivatele.csv (ve složce s projektem/bin/de­bug) a vidíme, že má následující obsah:

Pavel Slavík;22;21.3.2000
Jan Novák;31;30.10.2012

Vše tedy funguje, jak má :) Načtení uživatelů a dokončení aplikace si necháme na příště.


 

Stáhnout

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

 

  Aktivity (1)

Článek pro vás napsal David Čápka
Avatar
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 se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (7 hlasů) :
4.857144.857144.857144.857144.85714


 


Miniatura
Předchozí článek
Práce s textovými soubory v C#
Miniatura
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# část 2

 

 

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

Avatar
pracansky
Člen
Avatar
pracansky:

Možná jsem to přehlédl ale stálo by za zmínku proč tam máš ten @

 
Odpovědět 12.4.2015 17:39
Avatar
Odpovídá na pracansky
Ondřej Štorc:

@ se požívá na od escapeování znaků. V tomhle případě je to sice zbytečné, ale kdybys měl adresu třeba: "C:\Users\Ondra\­..\..\file.txt" tak místo toho abys psal "C:\\Users\\On­dra\\..\\..\\fi­le.txt" tak napíšeš jen @"C:\Users\On­dra\..\..\file­.txt"

Odpovědět 12.4.2015 18:11
Život je příliš krátký na to, abychom bezpečně odebírali USB z počítače..
Avatar
pracansky
Člen
Avatar
pracansky:

Není zbytečné nutné volat tu metodu Flush?
Předpokládá, že ukončením using bloku se zavolá Dispose které zavolá Close které zavolá Flush. Není možné přece soubor uzavřít dokud se ty data nezapíšou.
Nebo je to jinak?

 
Odpovědět  +2 12.4.2015 18:13
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na pracansky
Jan Vargovský:

Jop, interně se to flushuje. Minimálně u streamwriteru.

 
Odpovědět 12.4.2015 18:18
Avatar
ernee.gaming
Člen
Avatar
ernee.gaming:

Neměl by být v Uloz():

{
using (StreamWriter sw = new StreamWriter(this.soubor)
}

?

 
Odpovědět 4.8.2015 16:44
Avatar
lukas.kotyza
Člen
Avatar
lukas.kotyza:

jaky druh ukládání byste mi doporučili když potřebuji uložit data z 50 numericupdonwnů

 
Odpovědět 21. dubna 19:09
Avatar
Odpovídá na lukas.kotyza
Michal Štěpánek:

Trošku to upřesni, jak často chceš data měnit, přidávat, mazat, jak často se v nich chceš vrtat, vyhledávat, kolik jich cca může být celkem, co se s nimi má dít po uložení, nebo po načtení, atd...
Podle toho se pak odvíjí způsoby ukládání dat.

Odpovědět 21. dubna 21:29
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
lukas.kotyza
Člen
Avatar
Odpovídá na Michal Štěpánek
lukas.kotyza:

No potřeboval bych je načíst při otevření do numericupdownu, data změnit, uložit a zavřít to je vše

PS:nejlepší by bylo kdyby se uložili po každé změně ale to není nutné

 
Odpovědět 21. dubna 22:52
Avatar
Odpovídá na lukas.kotyza
Michal Štěpánek:

V tom případě je úplně šumák, jestli použiješ csv, txt nebo xml

Odpovědět 21. dubna 23:55
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
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 30. Zobrazit vše