Lekce 4 - Uložení objektů do CSV v C#
V minulé lekci, Práce s textovými soubory v 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 nebo na cokoli, co budete potřebovat evidovat.
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 inicializovat na základě
těchto 3 vlastností. Přepíšeme si metodu ToString()
tak, aby
vrátila 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řejnými metodami. 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í atribut
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() { } }
Visual Studio 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 List
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í StreamWriter
. 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)) { // 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). Zde vytvoříme privátní atribut databaze
, do
kterého v konstruktoru formuláře uložíme novou 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"
.
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žka s projektem/bin/debug
) 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í lekci, Uložení objektů do CSV v C# část 2.