Práce se soubory v jazyku C# V kapitole je rozebrána práce se soubory v jazyku C#. Je uvedeno dělení souborů, způsoby práce se soubory, třídy pro práci se soubory, použití objektů tříd StreamReader a StreamWriter ke čtení ze souboru a zápis do souboru. Pozornost je věnovaná též práci s binárními soubory s využitím tříd FileStream, BinaryWriter, BinaryReader. Látka je ilustrována řadou praktických příkladů. Klíčové pojmy: Soubory textové, binární, otevření a zavření souboru, režimy přístupu k souborům, třídy pro práci se soubory.
Pojem soubor Soubor je posloupnost znaků (bytů) ukončená speciální kombinací, která již do souboru nepatří. (EOF = End Of File). Se soubory je možné v programu pracovat i s využitím přesměrování vstupu a výstupu programu, známého z příkazového řádku.
Páce se soubory s využitím přesměrování vstupu a výstupu Přesměrování výstupu programu do souboru Standardní výstup programu je výpis na obrazovku a je možné ho přesměrovat do souboru: Nazev_spustitelneho_programu > nazev_souboru
Příklad: Pomocí následujícího příkazu cyklu vypíšeme ASCII tabulku na obrazovku: for (int i = 33; i < 255; i++) Console.Write("{0} {1}\t",(char)i,i);
Vytvoříme-li spustitelný soubor ascii.exe a přesměrujeme – li jeho výstup do souboru příkazem v aplikaci Příkazový řádek: znaky > soubor.txt,
program znaky.exe zapíše tabulku znaků a jejich kódů do souboru soubor.txt.
2.11.11
Práce se soubory v jazyku C#
1/22
Připojení výstupu programu do souboru Standardní výstup programu lze připojit do souboru: Nazev_spustitelneho_programu >> nazev_souboru
Příklad: Jestliže program spustíme z Příkazového řádku s následujícím přesměrováním: znaky >> soubor.txt,
program znaky.exe připojí tabulku znaků a jejich kódů do souboru soubor.txt Přesměrování vstupu programu ze souboru Standardní vstup z konzolové aplikace je z klávesnice. Pokud použijeme přesměrování: Nazev_spustitelneho_programu < nazev_souboru,
program bude číst data za souboru. Příklad: Má-li program následující zdrojový kód: string s; while(true){ s = Console.ReadLine(); if(s==null)break; Console.WriteLine(s); }
a soubor obsahuje data: Petr Pavel Josef
Po spuštění programu s uvedeným přesměrováním vstupu: program < soubor
se jména ze souboru vypíší na obrazovku. Dělení souborů Soubory dělíme na: Textové : řádky textu Binární : 1. hodnoty ve tvaru, jak jsou uloženy v paměti 2. nerozlišují se řádky 2.11.11
Práce se soubory v jazyku C#
2/22
Způsoby práce se soubory Čtení Zápis Připisování Kombinovaný přístup Jazyk C# rozlišuje soubory (file) a proudy (stream).
Třídy pro práci se soubory 1. S textovými: StreamReader, StreamWriter
2. Pro správu souborového systému: File, Direktory, FileInfo, DirectoryInfo
3. Práce s binárními soubory BinaryReader, BinaryWriter
Třída FileStream se používá, chceme-li definovat vlastnosti FileMode a FileAccess. Proud (stream) si můžeme představit jako nástroj pro přenos dat mezi zdrojem (např. programem) a spotřebičem (to může být nejen soubor, ale i síťové spojení, místo v paměti…). Zdrojem dat ovšem může být také soubor, nebo síťové spojení a spotřebičem program – záleží na okolnostech. Nástroje pro práci se soubory a vstupními a výstupními proudy jsou součástí knihovny a najdeme je v prostoru jmen System.IO Tento prostor obsahuje značné množství různých tříd – uvedeme si jen některé z nich. Hierarchie tříd ve jmenném prostoru System.IO :
2.11.11
Práce se soubory v jazyku C#
3/22
Třídy File a Directory Tyto třídy obsahují nástroje pro manipulaci se soubory a adresáři. Umožňují zjišťovat, zda soubor, nebo adresář existuje, vytvořit ho, přejmenovat, přesunout, zrušit, atd. Abstraktní třída Stream Tato třída je společným předkem tříd pro vstupní a výstupní operace. Od ní je odvozena mimo jiné třída FileStream, sloužící ke čtení ze souboru a zápisu do něj, třída MemoryStream pro přímou práci s pamětí a třída NetworkStream pro odesílání a přijímání dat prostřednictvím síťového spojení. Víme-li, že určitý soubor obsahuje text, je možné použít instance tříd StreamWriter a StreamReader pro zápis a čtení ze souboru. Tyto třídy pracují na vyšší úrovni a jsou pro čtení a úpravy obsahu textových souborů speciálně upraveny. Tyto třídy implementují metody pro čtení nebo zápis řádku textu: StreamReader.ReadLine()a StreamReader.WriteLine(), které se používají stejně, jako pro práci s konzolou: Console.ReadLine() a Console.WriteLine(). Při čtení proud automaticky vyhledá další konec řádku a skončí čtení právě na tomto místě. Při zápisu to znamená, že metoda automaticky přidá znak konce řádku. Třídy používají kódování založené na standardu Unicode. Abstraktní třída TextWriter Je předkem třídy StreamWriter, která poskytuje nástroje pro práci se znakovými proudy (zápis do textových souborů) Abstraktní třída TextReader Je předkem třídy StreamReader, která poskytuje nástroje pro práci se znakovými proudy (čtení z textových souborů)
Vytvoření objektu třídy StreamReader StreamReader jmeno_proudu = new StreamReader("jmeno_souboru");
Použití objektu třídy StreamReader ke čtení ze souboru Následující příklad vytvoří objekt sr třídy StreamReader a pomocí konstruktoru třídy StreamReader spojí tento proud se zdrojovým kódem programu Program.cs, který je umístěný o dvě složky výše, než vytvořený spustitelný soubor Program.exe - proto je uvedená relativní cesta k souboru: "..\\..\\Program.cs". Dále program přečte obsah celého souboru do proměnné myString metodou ReadToEnd(): StreamReader sr = new StreamReader("..\\..\\Program.cs"); string myString = sr.ReadToEnd();
2.11.11
Práce se soubory v jazyku C#
4/22
Načtení celého obsahu souboru do řetězcové proměnné Metodou ReadToEnd() načteme celý obsah souboru, spojeného s objektem sr do řetězcové proměnné myString. StreamReader sr = new StreamReader("..\\..\\Program.cs"); string myString; myString = sr.ReadToEnd();
Zavření souboru K zavření souboru použijeme metodu Close() aplikovanou na objekt třídy StreamReader nebo StreamWriter: sr.Close();
Relativní cesta do nadřazeného adresáře Pokud ve Visual Studiu vytvoříme vlastní textový soubor, uloží se v hierarchii složek o 3 úrovně výš, takže je třeba použít ..\\..\\..\\ Znak “\” je třeba zdvojit, neboť jednoduchý znak “\” uvádí Escape sekvenci. Příklad: Program, který vypisuje soubor.txt: using System; using System.IO; class Pokus { static void Main() { // Čtení souboru StreamReader sr = new StreamReader("..\\..\\..\\soubor.txt "); string s = sr.ReadToEnd(); sr.Close(); // Zobrazení obsahu souboru. Console.WriteLine(s); // Čekání na stisk klávesy. Console.ReadLine(); } }
Vysvětlení příkazů pro práci se soubory v uvedeném programu: StreamReader sr = new StreamReader("..\\..\\..\\soubor.txt");
uvedený příkaz otevře soubor.txt pro čtení a spojí ho s objektem sr. string s = sr.ReadToEnd();
Uvedený příkaz načte do řetězcové proměnné s obsah souboru soubor.txt. sr.Close();
Uvedený příkaz zavře soubor soubor.txt, spojený s objektem sr.
2.11.11
Práce se soubory v jazyku C#
5/22
Console.WriteLine(s);
Uvedený příkaz zobrazí obsah řetězce myString , do něhož se načetl obsah souboru soubor.txt . Volba kompilátoru Dáme-li před uvozovky s cestou a jménem souboru znak “@“, nemusíme “\“ v cestě zdvojit. @ je volba kompilátoru. Řetězec v uvozovkách se použije v tom tvaru, jak je uvedený. StreamReader sr = new StreamReader(@"..\..\soubor.txt");
Čtení souboru po řádcích Čtení ze souboru by mohlo proběhnout po řádcích v cyklu while, přičemž se testuje hodnota EndOfStream , která indikuje, zda běžná pozice v proudu je na konci proudu. Pokud ano, cyklus while končí. while (!sr.EndOfStream) { line = sr.ReadLine(); Console.WriteLine(line); }
Jiný způsob čtení a výpisu souboru po řádcích:
String line; System.IO.StreamReader sr = new System.IO.StreamReader(@"..\..\soubor.txt"); // Čtení a zobrazení řádků ze souboru, // dokud není dosažen konec souboru. while ((line = sr.ReadLine()) != null) { Console.WriteLine(line); } Console.ReadLine();
Test konce souboru Výše uvedený příklad ukazuje dvě možnosti testování konce souboru: 1. Test hodnoty EndOfStream , která indikuje, zda běžná pozice v proudu je na konci proudu 2. Test, zda načtený řetězec je různý od prázdné hodnoty null. Rozšíření jména souboru o cestu a příponu Spojení jména souboru s cestou a příponou:
Řetězce můžeme spojovat operátorem + string nazev="nazev";
// Čtení souboru System.IO.StreamReader myFile = new System.IO.StreamReader(@"..\..\..\"+nazev+".txt");
2.11.11
Práce se soubory v jazyku C#
6/22
Dále uvedený program umožňuje vybrat, který ze tří souborů (V2A.txt, V2B.txt, V2C.txt) chceme vypsat. Pomocí příkazu switch se do proměnné nazev uloží řetězcová konstanta V2A, nebo V2B, nebo V2C. int co;
string nazev ="V2A"; Console.WriteLine("Co chceš vypsat:"); Console.WriteLine("1 V2A"); Console.WriteLine("2 V2B"); Console.WriteLine("3 V2C\n"); co = Convert.ToInt32(Console.ReadLine()); switch (co) { case 1: nazev = "V2A"; break; case 2: nazev = "V2B"; break; case 3: nazev = "V2C"; break; } // Čtení souboru StreamReader sr = new StreamReader(@"..\..\..\"+nazev+".txt"); string s = sr.ReadToEnd(); s.ReadToEnd(); sr.Close(); // Zobrazení obsahu souboru. Console.WriteLine(s); // Čekání na stisk klávesy. Console.ReadLine();
Zápis do souboru Zápis do souboru provádíme pomocí objektu třídy StreamWriter , který pomocí konstruktoru této třídy spojíme s názvem konkrétního souboru, do kterého budeme zapisovat. Následující program zapíše do souboru jmena.txt řádky, zadané z klávesnice: String line; StreamWriter sr =new StreamWriter(@"..\..\jmena.txt"); while (true) { line = Console.ReadLine(); if (line == "konec") break; sr.WriteLine(line); } sr.Close();
Program čte jména z klávesnice a zapisuje je do souboru jmena.txt . Cyklus while , v němž zápis do souboru probíhá, je ukončen zadáním slova konec, které se už do souboru nezapíše.
2.11.11
Práce se soubory v jazyku C#
7/22
Režimy přístupu k souboru Jestliže pro vytvoření objektu pro práci se souborem použijeme třídu FileStream , můžeme zvolit režim přístupu k souboru: Append, Create, CreateNew, Open, OpenOrCreate.
Přidávání dat do souboru ilustruje následující program: Objekt fs je instance třídy FileStream Dále pomocí instance třídy FileStream vytvoříme instanci třídy StreamWriter : FileStream fs = new FileStream("jmena.txt", FileMode.Append); StreamWriter sw = new StreamWriter(fs); sw.WriteLine("Petr \r\nPavel \r\nJosef"); sw.Close();
Uvedený program přidá do souboru jmena.txt další tři jména. Možné módy souboru (FileMode): Append, Create, CreateNew, Open, OpenOrCreate, Truncate.
Zápis řetězců do souboru, jejich následné čtení a výpis na obrazovku using System; using System.IO; class Program { static void Main() { String line; StreamWriter sw = new StreamWriter(@"..\..\jmena.txt"); while (true) { line = Console.ReadLine(); if (line == "konec") break; sw.WriteLine(line); } sw.Close(); Console.Clear(); StreamReader sr = new StreamReader(@"..\..\jmena.txt"); string myString = sr.ReadToEnd(); sr.Close(); Console.WriteLine(myString); Console.ReadLine(); } }
Použití třídy ArrayList ve spojení se soubory Následující program vytvoří objekt ar třídy ArrayList . Jednotlivé řetězce jsou čteny z klávesnice v cyklu while do proměnné line a přidávány do objektu ar metodou Add(line) . Pole je následně setříděno metodou Sort() a zapsáno do souboru jmena.txtv cyklu for. Počet prvků v poli je určený pomocí vlastnosti Count. using System;
2.11.11
Práce se soubory v jazyku C#
8/22
using System.IO; using System.Collections; class Program { static void Main() { ArrayList ar = new ArrayList(); string line; while (true) { line = Console.ReadLine(); if (line == "konec") break; ar.Add(line); } ar.Sort(); StreamWriter sw = new StreamWriter(@"..\..\jmena.txt"); Console.Clear(); for (int i = 0; i < ar.Count; i++) { sw.WriteLine(ar[i]); Console.WriteLine(ar[i]); } sw.Close(); Console.ReadLine(); } }
2.11.11
Práce se soubory v jazyku C#
9/22
Správa souborového systému Třídy, které používáme k procházení souborového systému a k vykonávání různých operací, jako je přesouvání, kopírování a odstraňování souborů jsou znázorněny na následujícím diagramu. Jmenný prostor jednotlivých tříd je uveden v závorkách pod názvem příslušné třídy.
Význam jednotlivých tříd: Třída MarshalByRefObject je bázovou třídou všech tříd platformy .NET Framework používaných pro vzdálenou komunikaci. Umožňuje předávání dat (marshaling) mezi aplikačními doménami. Třída FileSystemInfo je bázovou třídou, která zastupuje souborový systém. Třída FileInfo a File zastupují soubory v souborovém systému. Třídy DirectoryInfo a Direktory zastupují složky souborového systému. Třída Path je třídou, obsahující statické členy používané k manipulaci se souborovými cestami. Třídy Directory a File obsahují pouze statické metody a nelze vytvořit jejich instance. Používají se zadáním souborové cesty k požadovanému objektu souborového systému. Chcete-li s dotyčným objektem souborového systému vykonat pouze jednu operaci, jsou to třídy výkonnější, protože nezatěžují systém tvorbou nových instancí. Třídy DirectoryInfo a FileInfo implementují prakticky stejné veřejné metody jako třídy Directory a File. Kromě toho nabízejí několik veřejných vlastností a konstruktorů. Jejich členy nejsou statické. Chcete-li je použít, musíte nejprve vytvořit jejich instance, které jsou spojeny s konkrétní složkou. Tyto třídy jsou efektivnější 2.11.11
Práce se soubory v jazyku C#
10/22
v případech, kdy s objekty souborového systému vykonáváte více operací. Instance si při svém vytvoření načtou potřebné informace a uchovávají si je po celou dobu existence. Test, zda soubor existuje Existenci souboru můžeme otestovat: Pomocí statické metody Exists("soubor") třídy File Pomocí vlastnosti Exists instance třídy FileInfo. Příklad: if (File.Exists(@"..\..\jmena.txt")) Console.WriteLine("Soubor existuje");
Jiný způsob testování existence souboru: Definujeme instanci třídy FileInfo:
FileInfo file = new FileInfo(@"..\..\jmena.txt"); if(file.Exists)Console.WriteLine("Soubor existuje");
Kopírování souboru Soubor můžeme kopírovat:
Pomocí statické metody Copy("zdroj","cíl",true) třídy File Pomocí nestatické metody CopyTo("cíl",true), použité na instanci třídy FileInfo.
Příklad: File.Copy(@"..\..\jmena.txt", @"..\..\jmena2.txt",true); nebo FileInfo file = new FileInfo(@"..\..\jmena.txt"); file.CopyTo(@"..\..\jmena3.txt",true);
Přesun souboru Soubor můžeme přesouvat:
Pomocí statické metody Move("zdroj","cíl",true) třídy File Pomocí nestatické metody MoveTo("cíl",true), použité na instanci třídy FileInfo.
Příklad: File.Move(@"..\..\jmena2.txt", @"..\..\jmena4.txt"); nebo FileInfo fi = new FileInfo(@"..\..\jmena3.txt"); fi.MoveTo(@"..\..\jmena5.txt");
2.11.11
Práce se soubory v jazyku C#
11/22
Smazání souboru Soubor můžeme smazat:
Pomocí statické metody Delete("soubor") třídy File Pomocí nestatické metody Delete(), použité na instanci třídy FileInfo.
Příklad: File.Delete(@"..\..\jmena2.txt"); nebo FileInfo file = new FileInfo(@"..\..\jmena3.txt"); file.Delete();
Některé vlastnosti objektů třídy FileInfo Objekty třídy FileInfo mají řadu vlastností. Některé vlastnosti objektu file třídy FileInfo jsou vidět z následujícího obrázku:
IsReadOnly LastAccessTime LastWriteTime Length
určí, nebo nastaví atribut Read Only souboru určí, nebo nastaví dobu posledního přístupu k souboru určí, nebo nastaví dobu posledního zápisu do souboru určí velikost souboru v bytech
Příklad: // Vytvoření objektu třídy FileInfo FileInfo file = new FileInfo("soubor"); // Výpis času posledního zápisu do souboru Console.WriteLine("Posledni zapis do souboru: {0}",file.LastWriteTime); // Výpis délky souboru Console.WriteLine("Delka souboru: {0}", file.Length );
Použití třídy Path - extrakce cesty k souboru Statická metoda GetDirectoryName(řetězec) třídy Path vrací informaci o adresáři pro specifikovanou cestu. 2.11.11
Práce se soubory v jazyku C#
12/22
Příklad: Console.WriteLine(Path.GetDirectoryName(@"C:\V2A\jmena.txt"));
Vypíše se: C:\V2A\
Metody třídy Directory Třída Directory obsahuje celou řadu metod pro práci s adresáři. Některé jsou vidět z následujícího obrázku.
Užitečné jsou statické metody GetFiles() a GetDirectories(). Metoda GetFiles(cesta) určí soubory v zadané složce a uloží je do pole řetězců. Metoda GetDirectories(cesta) určí všechny podadresáře ve specifikované složce a uloží je do pole řetězců. Příklad: Následující program vypíše obsah adresáře, zadaného v řetězcové proměnné cesta: C:\1011_skola .
K tomu jsou použity statické metody třídy Directory : GetFiles() a GetDirectories(). Metoda GetFiles(cesta) určí soubory v zadané složce a uloží je do pole řetězců soubory. Toto pole následně vypíšeme v cyklu foreach. Metoda GetDirectories(cesta) určí všechny podadresáře ve specifikované složce a uloží je do pole řetězců podadresare, které dále vypíše cyklem foreach. string cesta = @"C:\10-11_skola"; string[] soubory = Directory.GetFiles(cesta); foreach (string jmeno in soubory) Console.WriteLine(jmeno); Console.ReadLine(); string[] podadresare = Directory.GetDirectories(cesta); foreach (string jmeno in podadresare) Console.WriteLine(jmeno); Console.ReadLine();
2.11.11
Práce se soubory v jazyku C#
13/22
Čtení čísel ze souboru Čteme-li čísla ze souboru, v němž každé číslo je na zvláštním řádku, přečteme každý řádek metodou ReadLine() a načtený řetězec konvertujeme na příslušný datový typ. ReadLine() je nestatická metoda třídy StreamReader a pro její použití musíme vytvořit instanci třídy StreamReader. Příklad: Určení součtu a počtu sudých a lichých čísel v souboru: int num, s = 0, suda = 0, licha = 0; StreamReader sr = new StreamReader(@"..\..\cisla.txt"); // Čtení čísel ze souboru, // dokud není dosažen konec souboru. while (!sr.EndOfStream) { num = Convert.ToInt32(sr.ReadLine()); // Test na sudost if (num % 2 == 0) suda++; else licha++; s += num; } Console.WriteLine("Soucet: {0}\nPocet sudych: {1}\nPocet lichych: {2}",s ,suda,licha); Console.ReadLine();
Rozdělení načteného řetězce na podřetězce Pokud je v souboru uvedeno více čísel na jednom řádku, musíme načtený řetězec rozdělit na podřetězce metodou Split, která má jako argument definované pole možných oddělovačů jednotlivých čísel. Jsou-li například přípustnými oddělovači mezi čísly mezera a tabulátor, vytvoříme pole oddělovačů: char[] oddel = new char[] { ' ', '\t' };
Po načtení řetězce do řetězcové proměnné radek, rozdělíme načtený řetězec na podřetězce metodou Split(oddel). string radek= Console.ReadLine(); string[] split = radek.Split(oddel);
Metoda Split třídy string vrací pole řetězců, které obsahuje podřetězce načteného řetězce, oddělené definovanými oddělovači. Příklad: Program načte řetězec ze souboru texty.txt, oddělí v něm jednotlivá slova a vypíše je. StreamReader sr = new StreamReader(@"..\..\texty.txt"); char[] oddel = new char[] { ' ', '\t' }; string radek = sr.ReadLine(); string[] split = radek.Split(oddel); foreach (string s in split) Console.WriteLine(s);
2.11.11
Práce se soubory v jazyku C#
14/22
Uvedený zápis lze modifikovat tak, že pole oddělovačů vytvoříme přímo jako argument metody Split: StreamReader sr = new StreamReader(@"..\..\texty.txt"); string radek = sr.ReadLine(); string[] split = radek.Split(new Char[] { ' ', '\t' }); foreach (string s in split) Console.WriteLine(s);
Čtení více hodnot proměnných v jednom řádku
Řádek načteme pomocí metody ReadLine(); Pomocí definovaných oddělovačů a funkce Split rozdělíme řádek na podřetězce Podle potřeby podřetězce konvertujeme na požadovaný datový typ. Příklad: Máme soubor, který v každém řádku obsahuje dvě čísla, která máme sečíst. Program načte řádek ze souboru, rozdělí jej na podřetězce, ty konvertuje do odpovídajícího datového typu a vypíše jejich součet. Čtení řádků probíhá v cyklu while, v němž jsou zpracovány všechny řádky souboru cisla.txt. StreamReader sr = new StreamReader(@"..\..\cisla.txt"); string radek; double a, b; while(!sr.EndOfStream){ radek= sr.ReadLine(); string[] split = radek.Split(new Char[] { ' ' }); a = Convert.ToDouble(split[0]); b = Convert.ToDouble(split[1]); Console.WriteLine("{0} + {1} = {2}", a, b, a + b); }
Zpracování různorodých dat v souboru
Řádky čteme z proudu sr metodou ReadLine(); Pomocí definovaného pole oddělovačů a funkce Split rozdělíme řádek na podřetězce Jednotlivé podřetězce konvertujeme na odpovídající datové typy. Příklad: Předchozí příklad je rozšířený tak, že v souboru je kromě operandů i aritmetický operátor. Data v souboru cisla.txt jsou ve tvaru: 1,2 2,1 3,3 4,6 5,2
+ * / +
2,3 3,4 5,7 7,4 12,3
Program přečte řádek, rozdělí jej na podřetězce,které konvertuje na příslušný datový typ:
2.11.11
Práce se soubory v jazyku C#
15/22
První a třetí podřetězec jsou operandy – konvertuje podřetězce na double, druhý podřetězec je operátor – konvertuje jej na char. Pomocí přepínače vybere větev požadované aritmetické operace a vypíše výsledek. StreamReader sr = new StreamReader(@"..\..\cisla.txt"); string radek; double a, b; char c; while(!sr.EndOfStream){ radek= sr.ReadLine(); string[] split = radek.Split(new Char[] { ' ' }); a = Convert.ToDouble(split[0]); b = Convert.ToDouble(split[2]); c = Convert.ToChar(split[1]); switch(c){ case '+':Console.WriteLine("{0} {1} {2}= {3}",a,c,b,a+b);break; case '-':Console.WriteLine("{0} {1} {2}= {3}",a,c,b,a-b);break; case '*':Console.WriteLine("{0} {1} {2}= {3}",a,c,b,a*b);break; case '/':Console.WriteLine("{0} {1} {2}= {3}",a,c,b,a/b);break; } }
V/V binárních dat Výhody binárních souborů
Menší velikost (při ukládání čísel) Lepší utajení dat
Čtení/zápis z/do binárních souborů Pro čtení a zápis binárních dat používáme třídu FileStream. Její instanci můžeme získat buď pomocí metody Create() třídy File, nebo voláním konstruktoru třídy FileStream. Parametrem obou je znakový řetězec, představující cestu a jméno souboru a hodnota typu FileMode, udávající způsob otevření souboru.. Dále to může být hodnota typu FileAccess, udávající způsob přístupu k souboru a hodnota typu FileShare, udávající způsob sdílení souboru. Proud je po vytvoření automaticky otevřen a po skončení práce bychom ho měli uzavřít pomocí metody Close(). Pro čtení nebo zápis můžeme použít metody Read(), resp. Write(). Proud FileStream obvykle skládáme s proudy BinaryWriter, nebo BinaryReader, jak je vidět z následujícího příkladu. Nejprve je vytvořena instance FileStream, a tato je použitá pro vytvoření instancí tříd BinaryWriter a BinaryReader. Příklad: Zápis a čtení různých typů dat do/z binárního souboru: 2.11.11
Práce se soubory v jazyku C#
16/22
FileStream ds = new FileStream(@"c:\test.bin", FileMode.Create, FileAccess.ReadWrite); BinaryWriter w = new BinaryWriter(ds); w.Seek(0, SeekOrigin.Begin); int i = 100; w.Write(i);// zapis celeho cisla do souboru string text = "Toto je text"; w.Write(text);// zapis textu do souboru double d = 3.2; w.Write(d);// zapis racionalniho cisla do souboru BinaryReader r = new BinaryReader(ds); r.BaseStream.Position = 0;// nastaveni pozice v souboru i = 0; i = r.ReadInt32();// cteni celeho cisla ze souboru Console.WriteLine(i); text = String.Empty; text = r.ReadString();// cteni retezce ze souboru Console.WriteLine(text); d = 0; d = r.ReadDouble();// cteni racionalniho cisla ze souboru Console.WriteLine(d); w.Close(); ds.Close(); Console.ReadLine();
Náhodný přístup k datům Přístup k libovolnému místu v souboru K libovolnému místu v souboru lze přistoupit pomocí funkce Seek(int offset,
SeekOrigin origin) offset určuje posun v bytech vůči počátku (origin). Počátek může být: Počátek SeekOrigin.Begin; SeekOrigin.Current; SeekOrigin.End;
Význam Začátek souboru Aktuální pozice v souboru Konec souboru
Použitá funkce: w.Seek(0,SeekOrigin.Begin);
nastaví ukazatel v souboru na začátek.
Příklady práce se soubory.
2.11.11
Práce se soubory v jazyku C#
17/22
1. Třídění v souboru osoby.txt podle roku narození: Obsah souboru osoby.txt: Josef 1950 Praha Petr 1975 Brno Pavel 1980 Blansko Karel 1977 Ostrava Adam 1959 Cheb Zdenek 1939 Kladno Marie 1955 Praha Jarmila 1988 Brno
Je definovaná struktura Osoba, která obsahuje položky: jmeno, město, RokNar. Ve třídě Program je definované pole strukturovaných proměnných O, které mají strukturu Osoba . V Mainu jsou do tohoto pole načteny hodnoty ze souboru osoby.txt a druhý podřetězec v každém řádku, který odpovídá roku narození je konvertován na celé číslo. Třídění je provedeno statickou metodou trid(), která pole se strukturou Osoba třídí podle roku narození. Nakonec je vypsán setříděný výsledek. struct Osoba { public string jmeno; public string mesto; public int RokNar; } class Program{ static Osoba[] O = new Osoba[30]; static void prohod(ref Osoba O1, ref Osoba O2) { Osoba pom; pom = O1; O1 = O2; O2 = pom; } static void trid(int n) { int i, j; for (i = 0; i < n; i++) { for (j = i; j < n; j++) { if (O[i].RokNar > O[j].RokNar) prohod(ref O[i], ref O[j]); } } } static void Main() { StreamReader r = new StreamReader((@"..\..\osoby.txt")); int i = 0; while (!r.EndOfStream) {
2.11.11
Práce se soubory v jazyku C#
18/22
string[] s = r.ReadLine().Split(' '); O[i].jmeno = s[0]; O[i].RokNar = Convert.ToInt32(s[1]); O[i].mesto = s[2]; i++; } r.Close(); int n = i; trid(i); for (i = 0; i < n; i++) { Console.WriteLine("{0}\t{1}\t{2}", O[i].jmeno, O[i].RokNar, O[i].mesto); } Console.ReadLine(); } }
2. Zápis souřadnic do souboru Následující program umožňuje pomocí kurzorových šipek nakreslit obrazec v textovém t varu. Pozice kurzoru se nastavuje metodou SetCursorPosition(x, y) , přičemž x a y reagují na aktuální pozici kurzoru. Kromě zobrazení kurzoru na aktuální pozici se hodnoty x a y zapíší do souboru souradnice.txt. Vše probíhá v cyklu do-while, který se ukončí stiskem klávesy Escape. Data jsou v souboru zapsána ve tvaru: 41 42 43 44
12 12 12 12,
kde první číslo odpovídá souřadnici x a druhé souřadnici y. Na základě těchto souřadnic je možné vykreslit původní obrazec na obrazovku, jak ukáže následující příklad. public static void Main() { StreamWriter sw =new StreamWriter("souradnice.txt"); int x = 40, y = 12; ConsoleKeyInfo cki; Console.Clear(); Console.SetCursorPosition(40, 12); Console.Write("#"); do { cki = Console.ReadKey(false); switch (cki.Key) { case ConsoleKey.LeftArrow: x--; break; case ConsoleKey.UpArrow: y--; break; case ConsoleKey.RightArrow: x++; break; case ConsoleKey.DownArrow: y++; break; }
2.11.11
Práce se soubory v jazyku C#
19/22
Console.SetCursorPosition(x, y); sw.WriteLine("{0} {1}", x, y); Console.WriteLine("#"); } while (cki.Key != ConsoleKey.Escape); sw.Close(); }
// konec cyklu
3. Zápis nebo čtení ze souboru a vykreslování stopy Následující program umožňuje souřadnice kurzoru do souboru zapisovat, nebo je z něj číst podle volby uživatele. Nejprve vypíše nabídku a podle volby uživatele se program rozvětví příkazem if-else. Jestliže uživatel zvolí zápis, vytvoří se objekt třídy StreamWriter, pomocí kterého budou souřadnice do souboru zapisovány. Dále se kurzor nastaví do konzolového okna a vykreslí se znak "#". Při každém stisku kurzorové klávesy se změní souřadnice x a y, kurzor se nastaví na novou pozici a souřadnice se zapíší do souboru souradnice.txt. Opakování je zajištěno cyklem do-while, který trvá dokud uživatel nestiskne klávesu Escape. Potom je soubor uzavřen a program končí. Jestliže uživatel zvolí čtení, vytvoří se objekt třídy StreamReader, pomocí kterého budou souřadnice ze souboru čteny. V cyklu while, který probíhá, dokud nejsou přečtena všechna data ze souboru, je načten řádek, jsou odděleny a konvertovány hodnoty souřadnic x a y, kurzor je nastaven na tuto pozici a vypíše se tam znak "#". Nakonec je vstupní soubor uzavřen. public static void Main() { Console.WriteLine("Chces zapisovat nebo cist (1/2)"); int volba = Convert.ToInt32(Console.ReadLine()); Console.CursorVisible = false; if(volba == 1) { StreamWriter sw =new StreamWriter("souradnice.txt"); int x = 40, y = 12; ConsoleKeyInfo cki; Console.Clear(); Console.SetCursorPosition(40, 12); Console.Write("#"); do { cki = Console.ReadKey(false); switch (cki.Key) { case ConsoleKey.LeftArrow: x--; break; case ConsoleKey.UpArrow: y--; break; case ConsoleKey.RightArrow: x++; break; case ConsoleKey.DownArrow: y++; break; }
2.11.11
Práce se soubory v jazyku C#
20/22
Console.SetCursorPosition(x, y); sw.WriteLine("{0} {1}", x, y); Console.WriteLine("#"); } while (cki.Key != ConsoleKey.Escape); // end do-while sw.Close(); } else { string radek; int x, y; char[] oddel = new char[] { ' ' }; string[] sourad = new string[2]; StreamReader sr = new StreamReader("souradnice.txt"); while (!sr.EndOfStream) { radek = sr.ReadLine(); sourad = radek.Split(oddel); x = Convert.ToInt32(sourad[0]); y = Convert.ToInt32(sourad[1]); Console.SetCursorPosition(x, y); Console.WriteLine("#"); } sr.Close(); Console.ReadLine(); } }
4. Zobrazení obrázku Následující program zobrazí obrázek, který je uložený v kořenovém adresáři na disku C. Pro zobrazení je použita metoda DrawImage třídy Graphics . Před spuštěním programu je třeba:
zobrazit Solution Explorer
kliknout pravým tlačítkem na References
zvolit: Add Reference
na kartě .NET zvolit: Systém.Drawing a Systém.Windows.Forms Obrázky zobrazujeme metodou DrawImage, která má 5 parametrů: Objekt třídy Bitmap
Souřadnice horního rohu obrázku
Šířka a výška obrázku Metoda DrawImage je instantní a voláme ji pomocí objektu třídy Graphics using System; using System.Drawing; using System.Windows.Forms; class PaintEvent {
2.11.11
Práce se soubory v jazyku C#
21/22
public static void Main() { Form form = new Form(); form.Text = "Pejsek"; form.Paint += new PaintEventHandler(MyPaintHandler); Application.Run(form); } static void MyPaintHandler(object objSender, PaintEventArgs pea) { Graphics grfx = pea.Graphics; Bitmap bitmap = new Bitmap(@"c:\pes.jpg"); grfx.DrawImage(bitmap, 0, 0, 300, 300); } }
5. Přehrání souboru ve formátu mp3 using System; using System.IO; using System.Runtime.InteropServices; using System.Text; class Pokus { [DllImport("winmm.dll", EntryPoint = "mciSendStringA", CharSet = CharSet.Ansi)] protected static extern int mciSendString(string lpstrCommand, StringBuilder lpstrReturnString, int uReturnLength, IntPtr hwndCallback); static void Main() { int iReturn; iReturn = mciSendString(@"open c:\MP3\Broucci\VR0028.MP3", null, 0, IntPtr.Zero); iReturn = mciSendString(@"play c:\MP3\Broucci\VR0028.MP3", null, 0, IntPtr.Zero); Console.ReadLine(); } }
Shrnutí: V kapitole je rozebrána práce se soubory v jazyku C#. Je ukázána práce s textovými i binárními soubory s využitím tříd pro práci se soubory: StreamReader , StreamWriter, FileStream, BinaryReader, BinaryWriter. Je ukázáno i použití tříd k vykonávání různých operací se soubory, jako je přesouvání, kopírování a odstraňování souborů. Látka je ilustrována řadou praktických příkladů.
2.11.11
Práce se soubory v jazyku C#
22/22