Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 6 - Programujeme pro Windows 8 - Práce se soubory

V minulé lekci, Programujeme pro Windows 8 - Zachování stavu aplikace, jsme si ukázali jakým způsobem obsluhovat základní Life-Cycle aplikace.

V dnešním tutoriálu si ukážeme několik způsobů jak číst a zapisovat data do souborů.

Každá aplikace může zasahovat pouze do předem určených složek. Nemůžeme si vynutit uložení nějakého souboru mimo vyhrazené složky bez vědomí uživatele. Pokud budeme chtít uložit soubor mimo tyto speciální složky, musíme využít tzv. Pickery (viz. níže).

Složky

Ještě jednou složky, kam můžeme zasahovat bez vědomí uživatele. Složky jsou také označovány jako Isolated Storage, tedy Izolované úložiště.

  • Local Folder - složka pro soubory (.txt,.xml,obrazové soubory,...)
  • Roaming Folder - to samé jako Local s tím rozdílem, že tato složka se automaticky synchronizuje přes SkyDrive pokud ho má uživatel aktivní
  • Temp Folder - Složka pro dočasné soubory. Soubory po znovu otevření aplikace zmizí.
  • Local Settings - Místo pro ukládání různého nastavení. Je to datový kontejner. K hodnotám přistupujeme přes Klíče. Tedy Klíč - Hodnota
  • Roaming Settings - To samé jako Local Settings a opět synchronizování přes SkyDrive

Následující složky známe i z dřívějších systémů a ve WinRT jsou označovány jako KnownFolders

  • Documents - Složka určená pro dokumenty
  • Pictures - Složka pro obrázky
  • Videos - Složka pro video
  • Music - Složka pro audio

Pozn. Koho by zajímalo kde se Local / Roaming složky nacházejí tak je to zde: C:\Users\Jmeno­Uzivatele\Local\Pac­kages\APLIKACE. V packages mají aplikace jméno podle klíče. Musíte holt hledat :)

Uložení

Pojďme si tedy něco uložit. Uložíme pouze .txt soubor ve formátu CSV. Budeme mít databázi uživatelů (viz tento článek http://www.itnetwork.cz/…-souboru-csv od sdraco). Nebudu tu řešit žádný návrh aplikace a objektů. Předpokládám, že máme tedy List<Uzivatel> uzivatele. Každý má jméno, věk a datum registrace. Metoda pro uložení může vypadat následovně

public async Task<bool> UlozUzivatele()
{
    //zíká složku Local Folder
    StorageFolder folder = ApplicationData.Current.LocalFolder;

    //vytovří nový soubor asynchronně
    StorageFile file = await folder.CreateFileAsync("uzivatele.txt");

    try
    {
        // načte stream
        Stream stream = await file.OpenStreamForWriteAsync();

        //založí StreamWriter ze stream
        /*
         * Můžeme místo StreamWriter použít i FileIO a metodu jako WriteTextAsync
         * */
        using (StreamWriter writer = new StreamWriter(stream))
        {
            //Zapíšeme uživatele
            foreach (Uzivatel u in uzivatele)
            {
                await writer.WriteLineAsync(string.Format("{0},{1},{2}", u.Jmeno, u.Vek, u.Registrovan.ToString("d.M.y")));
            }
        }
        await stream.FlushAsync();
        return true;
    }
    catch
    {
        return false;
    }
}

Metoda je celkem prostá. Získáme složku, založíme soubor. Ze souboru vytvoříme stream a zapíšeme text. Stream poté uzavřeme. Určitě Vás ale zaráží jedna věc. Klíčová slova jako async a await už jsme jednou použili a opět vás zklamu. Dnes si to ještě nevysvětlíme. Berte to jako kouzelné slovíčko, které nám zajistí asynchronní běh metod. Celou metodu kvůli používání asynchroních metod StreamWriteru, Streamu apod musíme označit jako async! Tím říkáme, že zakládáme nové vlákno a kdekoliv je await, hlavní vlákno s UI běží (reaguje) stále dál a v pozadí se dějí další výpočty.

Především v prostředí Windows 8 aplikací se snažte o asynchronní přístup. Aplikace neprojde ani certifikací pokud vám hlavní vlákno s UI zamrzne!

Pokud async metoda potřebuje něco vracet, musí vracet objekt typu Task<T> nebo void.

Pokud chceme RoamingFolder, jednoduše načteme Roaming Folder a postup je stejný. Načítání myslím není potřeba ukazovat. Místo StreamWriter bychom použili StreamReader a ze složky bychom načetli soubor přes GetFileAsync(). Samozřejmě místo StreamWriteru / Readeru je možnost použít statickou třídu FileIO. Záleží na situaci a potřeby uložení.

XML Serializace

Formát CSV se hodí opravdu na pár skromných řádků dat. Mnohem lepší a přehlednější je XML formát. Máme zde stále možnost použít XmlReader / Writer. My si ukážeme jednodušší a rychlejší způsob, pokud chceme načíst vše a víme co přesně načítáme.

Hlavní třídou, která bude potřeba, je XmlSerializer. Třída která představuje data musí mít vždy konstruktor bez parametrů a samozřejmě klidně další s parametry. Skromná třída:

public class User
{
   public string Name{get;set;}
   public int Age{get;set;}

   private User()
   {}

  public User(string name,int age)
  {
    this.Name = name;
    this.Age = age;
  }
}

Data:

List<User> users = new List<User>(){
            new User("Pepa",15),
            new User("Vašek",25),
            new User("Jarmila",15)
        };

A kód pro serializaci a uložení

public async Task<bool> Uloz()
{
    try
    {
        StringWriter w = new StringWriter();
        //Načteme složku
        StorageFolder folder = ApplicationData.Current.RoamingFolder;
        //Vytvoříme soubor a v případě existence přemažeme
        StorageFile file = await folder.CreateFileAsync("notes.xml", CreationCollisionOption.ReplaceExisting);
        //Založíme Serializer typu List<User>
        XmlSerializer srl = new XmlSerializer(typeof(List<User>));

        //serializujeme
        srl.Serialize(w, users);

        //zapíšeme přes FileIO
        await FileIO.WriteTextAsync(file, w.ToString());
        // zavřeme StreamWriter
        await w.FlushAsync();

        return true;
    }
    catch
    {
        return false;
    }
}

Opět myslím, že kód mluví za vše :)

Obdobně bude načtení:

public async Task<bool> Nacti()
{
    try
    {
        // načteme složku
        StorageFolder folder = ApplicationData.Current.RoamingFolder;
        //načteme soubor
        StorageFile file  = await folder.GetFileAsync("users.xml");
        //založíme Serializer
        XmlSerializer srl = new XmlSerializer(typeof(List<User>));

        // přeteme text ze souboru (ještě stále XML formát)
        string text = await FileIO.ReadTextAsync(file);

        // založíme XmlReader
        XmlReader r = XmlReader.Create(new StringReader(text));
        //Deserializujeme a přetypujeme
        users = (List<User>)srl.Deserialize(r);

        return true;
    }
    catch
    {
        return false;
    }
}

Vidíme, že práce s XML je velmi snadná pokud nepotřebujeme vytáhnout určité části XML :)

Pickery

Picker je (s trochou nepřesnosti) komponenta, která umožňuje uživateli uložit / načíst soubor nebo otevřít složku pro čtení. Je to také jediný správný postup jak uložit data mimo určené složky. Uživatel vždy musí vědět co se mu děje na zařízení (PC,tablet, ...).

Pickerů máme tedy 3 typy

  • FileOpenPicker - načte jeden nebo více souborů
  • FileSavePicker - uloží jeden nebo více souborů do nastavené cesty
  • FolderPicker - umožní otevřít složku uvnitř aplikace

U FileOpenPicker a FolderPicker nalezneme jednu důležitou vlastnost a tím je FileTypeFilter. Jedná se o kolekci List<string> a udává jaký typ souborů můžeme otevřít / uložit. Pokud chceme všechny typy přidáme do kolekce hvězdičku() nebo určíme přesně typy souborů a to uvedením přípony: .txt,.xtml,.png,­... Obdobně u *FileSavePicker nalezneme vlastnost FileTypeChoices která udává co můžeme zvolit.

Ukázka Pickeru, který načte zvolený soubor.

FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".txt");
StorageFile file = await picker.PickSingleFileAsync();
IList<string> result = await FileIO.ReadLinesAsync(file, UnicodeEncoding.Utf8);

Pickery dokáží uložit i více souborů najednou. Určitě se podívejte na další nastavení Pickerů. Lze je různě stylovat :)

Settings

LocalSettings nebo RoamingSettings je speciální kontejner, kde můžeme snadno uchovávat hodnoty podle klíče. Je to jakýsi trvalý Dictionary. Myslím, že není zde co víc uvádět.

// uložení
ApplicationData.Current.LocalSettings.Values["name"] = "Zirko";

//načtení
string name = ApplicationData.Current.LocalSettings.Values["name"].ToString();

KnownFolders

Načtení a ukládání do KnownFolders je stejně jednoduché jako ostatní. Například Videos

StorageFolder videosFolder = KnownFolders.VideosLibrary;

Capabilities

S KnownFolders a s mnoha dalšími věcmi (v budoucnu si řekneme více) souvisí Package.appxma­nifest. V prvním díle jsme si o tomto souboru něco málo řekli. Pokud využíváte KnownFolders, musíte zaškrtnout tu library, kterou používáte a přidat deklarace. Ovšem už překračujeme dnešní náplň článku. Detailněji si to popíšeme jindy.

Dnešní článek byl velmi teoretický, v příští lekci, Programujeme pro Windows 8 - Vlastní styly v XAML se vrhneme na něco zajímavějšího :).


 

Předchozí článek
Programujeme pro Windows 8 - Zachování stavu aplikace
Všechny články v sekci
Windows 10 aplikace v C# .NET
Přeskočit článek
(nedoporučujeme)
Programujeme pro Windows 8 - Vlastní styly v XAML
Článek pro vás napsal Petr Nymsa
Avatar
Uživatelské hodnocení:
9 hlasů
Autor se věnuje programování v C# a celkově se zajímá o .NET technologie. Působí jako Microsoft Student Partner.
Aktivity