Práce s vlastními soubory v C# 2 - Ukládání a načítání zip
V minulém tutoriálu o vlastním formátu souborů jsme si představili možnosti archivů zip a založili projekt s formulářem pro zadání zaměstnance. V tomto díle se naučíme pracovat se složkou ZIP, ukládat a otevírat soubory vlastního typu.
Načítání hodnot do objektu zaměstnance
Nyní musíme do zaměstnance hodnoty z formuláře načíst. Přesuňme se zpátky ke kódu formuláře. Všem textovým polím přidejte stejnou obsluhu události pro KeyUp. V této obsluze dosaďte do zaměstnance hodnoty z textových polí. Metoda zároveň aktualizuje záhlaví okna. KeyUp proto, aby se událost nevyvolávala, když dosazujeme do políčka hodnoty z kódu. To bude jedna z dalších metod.
private void SynchronizacePoli(object sender, KeyEventArgs e) { zamestnanec.Jmeno = txtJmeno.Text; zamestnanec.Prijmeni = txtPrijmeni.Text; zamestnanec.Email = txtEmail.Text; zamestnanec.Telefon = txtTelefon.Text; this.Text = txtJmeno.Text + " " + txtPrijmeni.Text; }
Jediný prvek dtbNarozeni bude využívat události ValueChanged. V obsluze zaměstnanci dosadí svoji hodnotu.
private void dtpNarozeni_ValueChanged(object sender, EventArgs e) { zamestnanec.DatumNarozeni = dtpNarozeni.Value; }
Nyní budeme potřebovat opak a to nastavit hodnoty ze zaměstnance do formuláře. Toho využijeme když otevřeme soubor se zaměstnancem a budeme ho chtít načíst. Proto si napíšeme metodu AktualizujFormularovaData. Metoda dosadí do všech políček hodnoty ze zaměstnance. Metoda opět aktualizuje i záhlaví okna.
private void AktualizujFormularovaData() { txtJmeno.Text = zamestnanec.Jmeno; txtPrijmeni.Text = zamestnanec.Prijmeni; txtEmail.Text = zamestnanec.Email; txtTelefon.Text = zamestnanec.Telefon; dtpNarozeni.Value = zamestnanec.DatumNarozeni; pcbFoto.Image = zamestnanec.Foto; this.Text = txtJmeno.Text + " " + txtPrijmeni.Text; }
Ukládání souboru
Zaměstnanec bude mít metodu Uloz, která bude přijímat jediný parametr a to cestu k souboru *.zamestnanec. Metoda bude ukládat zaměstnance do zazipované složky se soubory foto.jpg a info.xml. Pro info.xml budeme potřebovat metodu, která vygeneruje xml a zapíše xml do archívu. V metodě budeme dost často pracovat s datovými proudy.
Nejprve si vytvoříme dočasnou složku, kam budeme data ukládat. Ukládat data přímo do archivu by totiž bylo zbytečně problémové. Využijeme metody Path.Combine, kterou zkombinujeme s AppData, složkou pro naši aplikaci a náhodným názvem. Tuto složku vytvoříme.
string cestaTemp = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"zamestnanci\", Path.GetRandomFileName()); Directory.CreateDirectory(cestaTemp);
Pomocí konstrukce Using vytvoříme datový proud pro soubor info.xml v naší dočasné složce.
using (FileStream fs = new FileStream(Path.Combine(cestaTemp, "info.xml"), FileMode.Create)) { UlozInfo(fs); }
Tento proud předáme privátní metodě UlozInfo, která do proudu zapíše XML.
private void UlozInfo(Stream proud)
Je na vás jestli XML zapíšete pomocí SAX, DOM nebo budete serializovat. V tomto článku to ani nebudu popisovat detailně. Můj kód exportu vypadá následovně.
XmlDocument doc = new XmlDocument(); XmlElement zamestnanci = doc.CreateElement("Zamestnanci"); XmlElement zamestnanec = doc.CreateElement("Zamestnanec"); zamestnanci.AppendChild(zamestnanec); XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", null); doc.AppendChild(dec); doc.AppendChild(zamestnanci); XmlElement Jmeno = doc.CreateElement("Jmeno"); Jmeno.AppendChild(doc.CreateTextNode(this.Jmeno)); XmlElement Prijmeni = doc.CreateElement("Prijmeni"); Prijmeni.AppendChild(doc.CreateTextNode(this.Prijmeni)); XmlElement Email = doc.CreateElement("Email"); Email.AppendChild(doc.CreateTextNode(this.Email)); XmlElement Telefon = doc.CreateElement("Telefon"); Telefon.AppendChild(doc.CreateTextNode(this.Telefon)); XmlElement DatumNarozeni = doc.CreateElement("DatumNarozeni"); DatumNarozeni.AppendChild(doc.CreateTextNode(this.DatumNarozeni.ToShortDateString())); zamestnanec.AppendChild(Jmeno); zamestnanec.AppendChild(Prijmeni); zamestnanec.AppendChild(Email); zamestnanec.AppendChild(Telefon); zamestnanec.AppendChild(DatumNarozeni); doc.Save(proud);
Nyní se vraťme k metodě Uloz. Vytvoříme další stream, tentokrát pro foto.jpg. Obrázek uložíme jeho metodou Save, která přijímá datový proud a výstupní formát. Díky výstupního formátu jsme schopni obrázek převést. Ačkoliv třeba uživatel vloží obrázek jako BMP, vždy bude v archivu uložen jako JPG.
using (FileStream fs = new FileStream(Path.Combine(cestaTemp, "foto.jpg"), FileMode.Create)) { this.Foto.Save(fs, ImageFormat.Jpeg); }
Zipování složky v C# .NET
.NET Framework 4.5 a výš obsahuje třídy pro práci se zipováním souborů. Jsou ve jmenném prostoru System.IO.Compression. Abyste však tyto jmenné prostory viděli, musíte si přidat k projektu 2 reference. V Solution Exploreru klikněte pravým tlačítkem na References > Add New Reference.
Do vyhledávacího políčka napište System.IO a označte reference System.IO.Compression a System.IO.Compression.FileSystem.
Dialog potvrďte. Do Using si přidejte odkazy na tyto knihovny.
Třída ZipFile má statickou metodu CreateFromDirectory, která přijímá dva parametry. První parametr je cesta ke složce, která má být zazipována a druhý je výsledný soubor. Tento soubor nemusí mít nutně příponu zip a toho využijeme. Víceméně však pouze metodě dosadíme cesty.
ZipFile.CreateFromDirectory(cestaTemp, soubor);
Vraťme se do formuláře. Vytvořte událost Click na objektu btnUlozit. Opět budeme vytvářet dialog. Protože filtr pro příponu zaměstnance použijeme 2× (otvírání a ukládaní), dáme ji třídě Zamestnanec jako statický člen.
public static string filter = "Soubor zaměstnance (*.zamestnanec)|*.zamestnanec";
Dialogu dosadíme výchozí název souboru, který bude vycházet ze jména a příjmení zaměstnance. Dialog otevřeme. Pokud vrátí OK, zaměstnance uložíme.
private void btnUlozit_Click(object sender, EventArgs e) { SaveFileDialog dialog = new SaveFileDialog(); dialog.Filter = Zamestnanec.filter; dialog.FileName = zamestnanec.Jmeno + " " + zamestnanec.Prijmeni; if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { zamestnanec.Uloz(dialog.FileName); } }
Aplikaci si spusťte. Vyberte nějakou fotku, vyplňte textová pole a nějaké datum. Zkuste zaměstnance uložit. Zkuste změnit jeho příponu na zip a podívejte se dovnitř. Bude tam fotka a soubor info.xml.
Otevíraní souborů v aplikaci
Otevíraní souboru budeme řešit v druhém přetíženém konstruktoru. Do konstruktoru nám v parametru bude předána cesta k souboru se zaměstnancem. Z tohoto souboru potřebuje získat datový proud, ten předáme v konstrukci Using konstruktoru třídy ZipArchive.
public Zamestnanec(string soubor) { using (FileStream fs = new FileStream(soubor, FileMode.Open)) { using (ZipArchive zip = new ZipArchive(fs)) { } } }
ZipArchive má metodu GetEntry, která vrátí ZipArchiveEntry. Ten obsahuje soubor uložený v archivu. ZipArchiveEntry má pak metodu Open, která vrací datový proud k souboru. Info.xml budeme načítat v metodě NactiInfo, které opět předáme datový proud a ta zpracuje XML.
ZipArchiveEntry info = zip.GetEntry("info.xml");
NactiInfo(info.Open());
NactiInfo můžete zase napsat více způsoby, já jsem použil DOM. Můj kód vypadá následovně.
private void NactiInfo(Stream proud) { XmlDocument doc = new XmlDocument(); using (XmlReader r = XmlReader.Create(proud)) { doc.Load(r); this.Jmeno = doc.GetElementsByTagName("Jmeno")[0].FirstChild.Value; this.Prijmeni = doc.GetElementsByTagName("Prijmeni")[0].FirstChild.Value; this.Email = doc.GetElementsByTagName("Email")[0].FirstChild.Value; this.Telefon = doc.GetElementsByTagName("Telefon")[0].FirstChild.Value; this.DatumNarozeni = DateTime.Parse(doc.GetElementsByTagName("DatumNarozeni")[0].FirstChild.Value); } }
Fotku načteme podobně, z datového proudu obrázek dostaneme pomocí statické metody Image.FromStream.
ZipArchiveEntry foto = zip.GetEntry("foto.jpg"); this.Foto = Image.FromStream(foto.Open());
Vraťme se k formuláři a vytvořte obsluhu události Click pro tlačítko otevřít. Opět vytvoříme dialog a opět mu načteme filtr. Otevřeme ho a porovnáme návratovou hodnotu s OK. Pokud uživatel soubor vybere, vytvoříme nového zaměstnance a v konstruktoru mu předáme cestu k souboru. Nakonec aktualizujeme data na formuláři, aby se změny ze zaměstnance projevily i na formuláři. Celá metoda by mohla vypadat následovně.
private void btnNacist_Click(object sender, EventArgs e) { OpenFileDialog dialog = new OpenFileDialog(); dialog.Filter = Zamestnanec.filter ; if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { zamestnanec = new Zamestnanec(dialog.FileName); AktualizujFormularovaData(); } }
Nyní je aplikace hotová, můžete vyzkoušet.
Aplikaci pořádně vyzkoušejte, příště se podíváme na možná vylepšení. Ošetříme chyby a vyšperkujeme soubory v průzkumníkovi Windows. V kódu pod článkem máte na testování přiloženého i plně validního zaměstnance Jana Nováka.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 259x (67.65 kB)
Aplikace je včetně zdrojových kódů v jazyce C#