NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!
NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.

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 AktualizujFor­mularovaData. 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.Com­pression. 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.

Visual Studio přidat referenci - Soubory v C# .NET

Do vyhledávacího políčka napište System.IO a označte reference System.IO.Com­pression a System.IO.Com­pression.File­System.

Přidat refernce System.IO.Compression - Soubory v C# .NET

Dialog potvrďte. Do Using si přidejte odkazy na tyto knihovny.

Třída ZipFile má statickou metodu CreateFromDirec­tory, 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.

Ukázka vyexportovaného zaměstnance - Soubory v C# .NET

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.

Načtení zaměstnance - Soubory v C# .NET

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#

 

Všechny články v sekci
Soubory v C# .NET
Článek pro vás napsal Michal Žůrek - misaz
Avatar
Uživatelské hodnocení:
2 hlasů
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.
Aktivity