5. díl - Uložení objektů do CSV v C# část 2

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

V minulém dílu seriálu tutoriálů o C# jsme načali databázi uživatelů pomocí CSV souborů. Nyní aplikaci dokončíme a doladíme.

Načtení uživatelů z CSV souboru

Uložení nám funguje, zbývá umět data opětovně načíst. Soubor budeme číst řádek po řádku, každý řádek rozdělíme metodou Split a následně do kolekce přidáme objekt s příslušnými hodnotami. Před načtením si kolekci vyprázdníme, aby při změně souboru v databázi nezůstal ten samý (kdyby se aplikace někdy rozšiřovala).

public void Nacti()
{
        uzivatele.Clear();
        // Otevře soubor pro čtení
        using (StreamReader sr = new StreamReader(soubor))
        {
                string s;
                // čte řádek po řádku
                while ((s = sr.ReadLine()) != null)
                {
                        // rozdělí string řádku podle středníků
                        string[] rozdeleno = s.Split(';');
                        string jmeno = rozdeleno[0];
                        int vek = int.Parse(rozdeleno[1]);
                        DateTime registrovan = DateTime.Parse(rozdeleno[2]);
                        // přidá uživatele s danými hodnotami
                        PridejUzivatele(jmeno, vek, registrovan);
                }
        }
}

Třída databáze je tedy kompletní. Nyní se zaměříme na formulářovou část.

Jako první si připravíme nové formulářové prvky (kontroly z ToolBoxu). Přidáme tlačítko načíst, dále ListBox listUzivatelu, u kterého nastavíme Sorted na true. Dále TextBox na jméno nového uživatele, NumericUpDown na jeho věk a DateTimePicker na datum registrace. Ke kontrolům přidáme nějaké labely. Tyto prvky můžeme seskupit do GroupBoxu. V dalším GroupBoxu budou 3 labely na detail uživatele, ty pojmenujeme labelJmena, labelVeku a labelRegistrace. Další 3 labely přidáme jako jejich popisek. Přidáme tlačítko k přidání uživatele a celou aplikaci můžeme oživit PictureBoxem. Pokud to bylo moc rychlé, nezoufejte, tady je obrázek výsledného formuláře:

Formulář databáze uživatelů v CSV

V reálu by bylo přidání uživatelů pravděpodobně přítomno v dalším formuláři, který by se zobrazoval jako dialog, ale nám to bude v tutoriálu stačit takto.

Z tlačítka Uložit odstraníme vytvoření testovacích uživatelů. Samotné uložení nyní vložíme do try-catch bloku. Víme totiž, že finally (tedy using blok v naší databázi) výjimky nepohlcuje, což také chceme a budeme na ně reagovat ve formulářové části, kam reakce logicky patří. Upozornění na chybu přímo ve třídě Databaze by bylo špatně. Po zachycení výjimky zobrazíme MessageBox s chybou. Metoda tlačítka bude tedy vypadat takto:

try
{
        databaze.Uloz();
}
catch
{
        MessageBox.Show("Databázi se nepodařilo uložit, zkontrolujte přístupová práva k souboru.",
                "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Obdobně naklikneme metodu tlačítka Načíst, pouze po načtení databáze vložíme objekty do ListBoxu. Ten předtím vymažeme, aby nám tam nezůstávali uživatelé z předešlého načtení. V reálu by se načtení vykonalo asi automaticky po spuštění aplikace a uložení po ukončení, pro názornost si to však ponecháme na tlačítkách. Metoda tlačítka Načíst tedy vypadá takto:

try
{
        databaze.Nacti();
        listUzivatelu.Items.Clear();
        listUzivatelu.Items.AddRange(databaze.VratVsechny());
}
catch
{
        MessageBox.Show("Databázi se nepodařilo načíst, soubor zřejmě neexisituje.",
                "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Nyní zpracujeme kliknutí na listUzivatelu, které provede zobrazení detailu uživatele do připravených labelů:

if (listUzivatelu.SelectedItem != null)
{
        Uzivatel u = (Uzivatel)listUzivatelu.SelectedItem;
        labelJmena.Text = u.Jmeno;
        labelVeku.Text = u.Vek.ToString();
        labelRegistrace.Text = u.Registrovan.ToShortDateString();
}

Kód jsme opodmínkovali pro případ, že by nebyl žádný uživatel vybrán (list by byl prázdný), za řeč stojí přetypování označené položky na typ Uzivatel, jelikož ListBox není generická kolekce a C# tedy neví, jakého je item typu. Můžete si vyzkoušet, že vše funguje.

Poslední tlačítko bez metody je Přidání nového uživatele. Rozklikneme ho tedy, vložení bude velmi jednoduché, prvek ovšem musíme přidat jak do databáze, tak do listUzivatelu. U složitějších aplikací bychom použili tzv. databinding, ale nás by to nyní jen pletlo.

private void tlacitkoPridat_Click(object sender, EventArgs e)
{
        string jmeno = jmenoTextBox.Text;
        int vek = Convert.ToInt32(vekNumericUpDown.Value);
        DateTime registrovan = registrovanDateTimePicker.Value;
        databaze.PridejUzivatele(jmeno, vek, registrovan);
        listUzivatelu.Items.Add(new Uzivatel(jmeno, vek, registrovan));
}

Zkusíme přidat nového uživatele:

Formulář databáze uživatelů v CSV

Podobně bychom si mohli napsat i mazání uživatelů, ale to již nechám na vás. Zbývá nám ještě ošetřit cestu k souboru, aby vedla do složky AppData, nikoli do složky s programem. To umíme z tutoriálu Úvod do práce se soubory . Také bychom mohli vymazat text labelů při startu programu. Obojí vykonáme v konstruktoru formuláře, do using si přidáme System.IO.

public Form1()
{
        InitializeComponent();
        // vyprázdnění labelů detailu uživatele
        labelJmena.Text = "";
        labelVeku.Text = "";
        labelRegistrace.Text = "";
        // vytvoření složky aplikace v AppData
        string cesta = "";
        try
        {
                cesta = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "DatabazeUzivatelu");
                if (!Directory.Exists(cesta))
                        Directory.CreateDirectory(cesta);
        }
        catch
        {
                 MessageBox.Show("Nepodařilo se vytvořit složku " + cesta + ", zkontrolujte prosím svá oprávnění.",
                   "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        // vytvoření databáze
        databaze = new Databaze(Path.Combine(cesta, "uzivatele.csv"));
}

A je to :)

Naše aplikace je téměř hotová, ještě se zamyslíme nad tím, co se stane, když někdo do jména vloží středník. Aplikace se rozbije. Proto budeme v metodě Uloz() středníky ze jména odstraňovat. Kdybychom dělali aplikaci, kde bychom je potřebovali (což se nestává příliš často), můžeme vybrat jiný zástupný znak. Pokud bychom chtěli být dokonalí, vložíme takovou hodnotu se středníkem do uvozovek. Poté se však již nejedná o jednoduché CSV a metoda Split nám přestane stačit, zájemce odkáži na třídu Microsoft.Visu­alBasic.FileI­O.TextFieldPar­ser. Dále by se to samozřejmě dalo řešit jiným formátem. My si tedy středníky pouze odstraňme, přesněji je nahradíme mezerami změnou jediného řádku v metodě Uloz():

string[] hodnoty = { u.Jmeno.Replace(';',' '), u.Vek.ToString(), u.Registrovan.ToShortDateString() };

A jsme hotoví. Pokud vám něco nešlo úplně hladce, hotový projekt máte jako vždy v příloze i se zdrojovým kódem. Příště se podíváme na formát XML.


 

Stáhnout

Staženo 813x (82.14 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.428574.428574.428574.42857 4.42857


 


Miniatura
Předchozí článek
Uložení objektů do CSV v C#
Miniatura
Všechny články v sekci
Práce se soubory v C#

 

 

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

Avatar
Jan Vargovský
Redaktor
Avatar
Jan Vargovský:

No musel bys upravit název toho souboru.

soubor = "test" + DateTime.Now.ToString("_dd_MM_yyyy_hh_mm") + ".csv

Btw, pak si budeš upravit i to načítání.

Editováno 13.5.2014 12:11
 
Odpovědět 13.5.2014 12:09
Avatar
ipad
Člen
Avatar
Odpovídá na Jan Vargovský
ipad:

Je to OK.
Ešte otázka: keď vytvorím SETUP a spustím program vo Win7/32bit - je OK ak spustím program vo Win7/64bit pri uložení súboru nanajde cestu na uloženie.
Ďakujem

 
Odpovědět 13.5.2014 16:19
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na ipad
Jan Vargovský:

Se koukni jak se ty cesty změnily, ne?

 
Odpovědět 13.5.2014 17:11
Avatar
kamo20101
Člen
Avatar
kamo20101:

Ja sa snzyim vzmazat objekt z listu a zase to nacitat do listboxu ale nejde to a uz neviem ako dalej, poradte mi kde je chzba

void DeleteClick(object sender, EventArgs e)
{
Databaza db=new Databaza(@"d:\u­sers.txt");
Uzivatel a=(Uzivatel)lis­tBox1.Selecte­dItem;
db.Vymaz(a);
listBox1.Item­s.Clear();
listBox1.Item­s.AddRange(db­.Vrat());

}
public void Vymaz(Uzivatel zmaz)
{
uzivatelia.Re­move(zmaz);
}

Editováno 16.5.2014 21:31
 
Odpovědět 16.5.2014 21:30
Avatar
kamo20101
Člen
Avatar
kamo20101:

presne takto som to spravil aj ja ale objekt sa mi nevymaze. uz sa s tym trapim druhy den neviem ci by som nemal override equals metodu aby porovnavala nejake id z listu.

 
Odpovědět 18.5.2014 0:03
Avatar
pracansky
Člen
Avatar
pracansky:

Jedna poznámka ke konverzi. Memetoda ToShortDateString() vrací text podle regionálního nastavení. To znamená že při načítání v počítači s jiným nastavením nemusí fungovat.
Mělo by se to ukládat v explicitním formátu.

pěkným příkladem je desetinná tečka a čárka, případně lomítko v americkém datumu.

A jak už je psáno výše csv je dobré na tyhle příklady:) ale jinak je lepší JSON/XML

 
Odpovědět 12.4.2015 17:56
Avatar
Patrik Bak
Člen
Avatar
Patrik Bak:

Ahojte. Chcem uložiť nejaký objekt do CSV, ktorý okrem bežných vlastností dátoveho typu string, int obsahuje aj vlastnosť typu list<int> a tiež dátový typ istého "enum". Skonvertovať string na enum hádam pôjde, ako si ale poradiť s listom ? Zapísať ho pomocou iného separátora ako jeden string a tak to skonvertovať ? Nie je na toto lepšie použiť niečo iné ako CSV ?

 
Odpovědět 7.8.2015 2:45
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Patrik Bak
Jan Vargovský:

Jestliže má ten objekt relace, tak urcite pouzij jiny formát. Jestliže je ta relace třeba jen list čísel, tak je zlo jako poslední na řádku.

 
Odpovědět 7.8.2015 8:16
Avatar
Patrik Bak
Člen
Avatar
Odpovídá na Jan Vargovský
Patrik Bak:

"Jestliže má ten objekt relace", Čo sa tým prosím myslí ?

 
Odpovědět 7.8.2015 11:37
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Patrik Bak
Jan Vargovský:

Ze má objekt referenci na další objekt.

 
Odpovědět 7.8.2015 12:18
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 53. Zobrazit vše