690 likes | 905 Vues
Fájlkezelés . Net-ben. Készítette: Major Péter. Előszó. Az alábbi diavetítés tömören összefoglalja a .Net-es fájlkezelés sajátosságait.
E N D
Fájlkezelés .Net-ben Készítette: Major Péter
Előszó • Az alábbi diavetítés tömören összefoglalja a .Net-es fájlkezelés sajátosságait. • A diák számos parancsot ismertetnek, de ezeket nem kell fejből tudni, hiszen azokat a Visual Studio bevitelkor felajánlja, megjeleníti azok feladatát, és paramétereik jelentését (angolul). Ennél sokkal fontosabb, hogy tudjuk milyen parancsok vannak, hiszen ezen építőelemekből építjük fel programunkat. • Ha egy parancson állva F1-et nyomunk megjelenik annak részletes leírása, sok esetben példaprogrammal együtt. • Itt nem kerül ismertetésre az összes lehetőség, ezért a kódkiegészítő listáit és a súgót böngészve mindig érdemes szétnézni, mielőtt egy esetleg már megoldott probléma implementálásába kezdünk. (Persze ettől még mi is megoldhatjuk a problémát, hiszen sok esetben több funkciót vagy nagy sebességet csak így kaphatunk.)
A System.IO névtér • A .Net keretrendszerben a fájlrendszerrel kapcsolatos műveleteket magába foglaló névtér a System.IO. • Osztályai többek közt az alábbi funkciókat valósítják meg: • Fájlok: • Létrehozása, törlése • Mozgatása/Átnevezése • Írása, olvasása • Fájlinformációk (pl.: módosítás ideje) elérése • Könyvtárak: • Létrehozása, törlése, mozgatása • Könyvtárinformációk (pl.: létrehozás ideje) elérése • Elérési utak kezelése (Path osztály) • Adatfolyamok kezelésének alaposztályait definiálja, amit pl.: a System.Net névtér számos eleme használ
Elérési utak kezelése • Az elérési utakban található „\” (backslash) karakter a C# nyelvben speciális szerepet játszik, úgynevezett menekülő karakter, mely az utána lévő karakter speciális kezelését vonja maga után. • Ez teszi lehetővé pl.: " elhelyezését egy stringben vagy új sor kezdését: • "Hello \"world\"!" • "Új sor:\r\n" • Ezért az elérési utakat így adhatjuk meg: • string path="F:\\Axodox\\Dokumentumok\\E-book"; • stringpath2=@"F:\Axodox\Dokumentumok\E-book";
A Path osztály • A fájlkezelő műveletek során sokszor szükség van elérési utak manipulációjára, ezt a System.IO.Path statikus osztály hívatott megkönnyíteni. Az alábbi függvényekkel egy elérési utat tároló stringből nyerhetőek ki információk: • stringGetDirectoryName(stringpath): elérési út a fájlnév és az utolsó perjel nélkül • stringGetFileName(stringpath): a fájl neve kiterjesztéssel • stringGetFileNameWithoutExtension(stringpath): a fájl neve kiterjesztés nélkül • stringGetExtension(stringpath): a kiterjesztés
A Directory és File statikus osztályok • A System.IO.Directory és System.IO.File osztályok a könytár- és fájlkezeléssel kapcsolatos műveleteket valósítják meg. (Olyanokra kell gondolni pl.: Windows Intézőben fájlmásolás, könyvtárlétrehozás stb.) • Statikus osztályok, nem példányosíthatóak, tehát függvényeik pl.: a Directory.GetCurrentDirectory() formában hívhatóak. (usingSystem.IO; esetén) • A következőkben röviden összefoglalom az ide kötődő függvényeket, melyek feladatát nevük is jól tükrözi. • Itt most csak a fontosabb függvényeket ismertetem, a többit név alapján is könnyen kiválaszthatjuk VisualStudio-ban a Ctrl+Space lenyomásával előugró listából.
A Directory osztály fontosabb tagfüggvényei • DirectoryInfoCreateDirectory(stringpath): a megadott elérési út összes nem létező elemét létrehozza • voidDelete(stringpath[, boolrecursive]): törli a megadott könyvtárat (ha üres!), ha a „recursive” igaz, akkor az összes bennfoglalt fájlt és könyvtárat is törli • boolExists(stringpath): lekérdezi, hogy létezik-e a könyvtár • string[]GetDirectories(stringpath): megadja a könyvtárban található alkönyvtárak listáját (teljes elérési úttal) • string[]GetFiles(stringpath[, stringsearchPattern]): megadja a könyvtárban található fájlok listáját (teljes elérési úttal), a „searchPattern” paraméterrel „munka?_*.txt” stílusban szűrhetünk is • string[]GetFileSystemEntries(stringpath): az előző kettő együtt
A Directory osztály fontosabb tagfüggvényei • stringGetCurrentDirectory(): az aktuális könyvtárat adja vissza • (Ez nem mindig egyezik meg a jelenleg futó program (*.exe, *.dll) helyével, amit egyébként a System.Reflection.Assembly. GetExecutingAssembly().Location paraméterből nyerhetünk ki) • voidMove(stringsourceDirName,stringdestDirName): a könyvtár mozgatása a forrásból (sourceDirName) a célkönyvtárba (destDirName)
A File osztály fontosabb tagfüggvényei • boolExists(string path): ellenőrzi a megadott fájl létezését • voidMove(stringsourceFileName,stringdestFileName): a fájl mozgatása forrásból a célba • voidCopy(stringsourceFileName,stringdestFileName): a fájl másolása forrásból a célba (létező fájl így nem írható felül) • voidDelete(stringpath): fájl törlése • A többi fontosabb tagfüggvény később kerül ismertetésre.
Karakterkódolás • A szöveges fájlok különféle módon tárolhatják bináris formában a szöveget. • A kódolások egyik fő jellemzője, hogy egy karaktert hány bájton tárolnak, hiszen ez szabja meg, hogy hány különféle betű és jel használható. • A legelterjedtebb karakterkódolások: • ASCII - American Standard CodeforInformationInterchange – 1bájt / kar., első 128 állandó jel, a többi a nyelvi beállítástól függ (ő, ű betűk) • UTF - Unicode TransformationFormat – 256^4 jel, több változata létezik – de a legfontosabb az UTF-8 (és még az UTF-7): • Kompatibilis az ASCII-vel mivel az első 128 jel kódolása megegyezik • 1-4 bájt / karakter (gyakori karakterekhez rövidebb jel) • Ma az egyik legelterjedtebb kódolás, mert helytakarékos és a teljes UTF karakterkészletet képes leírni.
Karakterkódolás a .NET-ben • A System.Text.Encoding osztály tagjaival, pl.: • Encoding.ASCII • Encoding.UTF8 • Minden osztálynak az Encoding-ban van egy: • byte[]GetBytes(string text): visszaadja a text-nek megfelelő bájtömböt az adott kódolásban • stringGetString(byte[] bytes, int index, intcount): visszaadja a bytes tömbnek megfelelő string-et (az „index” a kezdő index a bájttömbben, a „count” a kikódolandó bájtok száma) • Ezen osztály elemeit kell megadni számos a szövegfájlokat kezelő parancsnak.
Szöveges fájlok kezelése • Bár az adatok tárolása bináris formában hatékonyabb lehet, mint szöveges leírással, ennek ellenére számos esetben fontos szempont az, hogy egy fájlt pl.: notepad-el megnyitva is könnyen olvashassunk szerkeszthessünk. • A szöveges fájlok kezelésére több lehetőségünk van: • Egy egész fájl létrehozása/olvasása/írása egyetlen paranccsal egy string-ből/be (ReadAllText stb.) • Kezelés adatfolyamként (StreamReader, StreamWriter) • A .Net bináris fájlok kezelésére szolgáló parancsaival is írhatunk szöveget fájlba. (úgy hogy pl. notepad-ban az látható lesz)
Egyszerű szövegfájl kezelési parancsok • voidWriteAllLines(string path,string[]contents[,Encoding encoding] ): szöveg fájlba írása egy string tömbből (contents), a megadott kódolással (encoding), felülír ha már létezik • string[]ReadAllLines(string path,Encodingencoding): szövegfájl beolvasása tömbbe, melynek minden eleme egy sor • voidWriteAllText( stringpath, stringcontents, Encodingencoding ): egyetlen string fájlba írása, felülír ha már létezik • stringReadAllText(string path,Encoding encoding): szövegfájl beolvasása stringbe • voidAppendAllText( string path, string contents ): szöveg hozzáadása a fájl végéhez, ha nem létezik létrehozza • Ezen parancsokat egyszerűbb esetekben használhatjuk.
Az adatfolyamok elméleti háttere • Az adatfolyam tulajdonképpen egy adatsorozatot (bájtsorozatot, karaktersorozatot) jelképező absztrakció. • Egy adatfolyam a következő funkciókat nyújtja: • Adatokat olvashatunk ki valamilyen típusú változóba. • Egy változó tartalmát kiírhatjuk az adatfolyamba. • Az írás/olvasás pozíció változással jár, az hogy ezen kívül mozoghatunk-e az attól függ mit képez le az adatfolyam: • Például egy szövegfájlban tetszőleges mozoghatunk (a fájl határán belül). • De egy TCP adatfolyam olvasásakor ezt nyilván nem tehetjük meg.
Fájl kezelés folyamata • A fájlt először meg kell nyitnunk, ilyenkor meg kell adni annak helyét, a megnyitás módját (írás/olvasás), és megadható a fájl zárolása. (pl.: miközben írunk egy nagy fájlt azt közbe ne lehessen megnyitni) • A fájl írása/olvasása, mozgás a fájlban. • Flush művelet: íráskor az adatok nem kerülnek közvetlenül a háttértárra, hanem egy ideig a memóriában pufferelődnek, ha kell kényszeríthetjük az adatok kiírását (nagy fájlok, hibanapló). • A fájl bezárása (automatikusan flush) és az erőforrások felszabadítása.
A StreamReader osztály • A System.IO.StreamReader osztály segítségével szövegfájlok tartalmát olvashatjuk be. • Főbb tagfüggvényei és mezői: • StreamReader( string path, Encodingencoding ): a konstruktornak a fájl elérési útját és a használandó karakterkódolást kell megadni • intRead( char[] buffer, int index, int count ): beolvasás karaktertömbbe, az „index” a céltömbre vonatkozik, a „count” a kiolvasandó karakterek maximális száma, a visszatérési érték a kiolvasott elemek száma • (Az előző parancsnak van egy ReadBlock változata is, amely ugyanilyen formájú, a különbség abban rejlik, hogy ez addig blokkolja az adott szálat, amíg nem áll rendelkezésre elég adat, ennek pl.: hálózati adatfolyamok esetében van jelentősége.)
A StreamReader osztály • stringReadLine(): egy sor beolvasása • stringReadToEnd(): az egész adatfolyam beolvasása • boolEndOfStream { get; }: megadja, hogy végére értünk-e az adatfolyamnak • voidClose(): az adatfolyam lezárása, erőforrások felszabadítása (meghívja a Dispose-t is)
A StreamWriter osztály • A System.IO.StreamWriter osztállyal egyszerűen elvégezhető szövegfájlok létrehozása. • Főbb tagfüggvényei és mezői: • StreamWriter( string path, bool append, Encodingencoding ): konstruktor, a „path”-ban megadott fájlt megnyitja írásra, az „append” bekapcsolásával létező fájlhoz fűzhetünk hozzá, nélküle ilyenkor felülírás történik, az „encoding”-al megadhatjuk a szöveg kódolását • voidWrite( stringvalue ): adat kiírása adatfolyamba, számos túltöltött verzióval rendelkezik sok adattípushoz (int, double, bool stb.) • voidWriteLine( stringvalue ): ugyanaz, mint az előző, de sortörést is beszúr az adatfolyamba
A StreamWriter osztály • voidFlush(): kényszeríti az adatok azonnali kiírását a adatfolyamba • boolAutoFlush { get; set; }: automatikus adatkiírás az adatfolyamba • voidClose(): az adatfolyam lezárása, erőforrások felszabadítása (meghívja a Dispose-t is) • Az itt ismertetett osztályokkal általános (System.IO.Stream-ből leszármazó) adatfolyamba is írhatunk, ekkor a konstruktor egy másik formáját használjuk.
Egyszerű példaprogram using System; usingSystem.IO; usingSystem.Text; namespacegyak_file { classProgram { staticvoid Main(string[] args) { //A második paraméter: a hozzáfűzés StreamWriter SW = newStreamWriter("text.txt", false, Encoding.UTF8); SW.Write("Ez egy szövegfájl."); SW.WriteLine(" Új sort kéne kezdeni."); SW.Write("Amit így is lehet:\r\n"); SW.WriteLine("Itt a vége?"); //A parancsok az összes fontos .Net típushoz tartalmaznak overloadot SW.WriteLine(true); SW.Flush(); //Ha itt hiba miatt leállna a program futása, //a flush miatt az eddig beadott szöveg már kiolvasható lenne a fájlból. SW.WriteLine("Viszlát!"); SW.Close(); SW.Dispose(); } } } //A létrejött fájl tartalma: Ez egy szövegfájl. Új sort kéne kezdeni. Amit így is lehet: Itt a vége? True Viszlát!
Feladat • Ön egy kisvállalkozásnál dolgozik, mint tervezőmérnök. Az esetleges adatvesztések elkerülése miatt főnöke megkéri, hogy az összes munkáját rendszeresen mentse át egy központi szerverre. • Ön több egymástól különböző könyvtárban található fájlokon dolgozik egyszerre. (pl.: egy végeselemes modellt készít egy számítógéppel tervezett alkatrészről, és közben jelentést is ír róla.) • A gyakori másolgatás folyamatosan megszakítja munkájában. Eszébe jut, hogy egyszerűbb lenne egy célprogramot használni a biztonsági mentésekhez, és az egyetemen szerzett C# ismeretei felhasználásával ezt el is tudná készíteni. BackUpTools (+)
BackUpTools • Készítsen programot, mely egy szöveges fájlból beolvassa, milyen könyvtárakból, hová, milyen típusú fájlokat kell átmásolnia. • A másolást csak akkor végezze el, ha az szükséges: • Ha még nincs biztonsági másolat a fájlról • Vagy van másolat, de az régebbi, mint az eredeti • A program ne tartalmazzon grafikus felületet, hiszen a háttérben fog futni, így feleslegesen foglalna le erőforrásokat. • A program a folyamat állapotát terminálablakban mutassa és rögzítse naplófájlba is. • A feladatot tartalmazó fájlt argumentumként lehessen megadni a program elindításakor, így azt a Windows feladatütemezőhöz adva az automatikus biztonsági mentés megoldható. BackUpTools (+)
Egyszerű naplózó osztály készítése publicclassLog { publicbool Closed { get; privateset; } //Lezártuk-e már a fájlt? StreamWriter SW; //A szöveg fájl írásához szükséges StreamWriter boolError; //Hiba történt //Gyárfüggvény //Azért használunk gyárfüggvényt, mert ha eleve nem tudjuk a fájlt létrehozni, //nincs mit csinálni az osztállyal publicstaticLogFromFile(string path, Encoding encoding) { try { //Megnyitás hozzáfűzésre(!) StreamWriterstreamWriter = newStreamWriter(path, true, encoding); returnnewLog(streamWriter); } catch//Ha hiba történt null-t adunk vissza { returnnull; } } private Log(StreamWriter streamWriter) //Privát(!) konstruktor a gyárfüggvényhez { Error = false; SW = streamWriter; Add("Log opened."); } … BackUpTools (+) //Az osztály használata: log = Log.FromFile("log.txt", Encoding.UTF8); log.Add("Napló szöveg 1"); log.Close();
Egyszerű naplózó osztály készítése … publicvoid Add(string text) //Szöveg hozzáadása { if (!Closed) //Ha mégnemzártuk le { try { string line = DateTime.Now.ToString() + ": " + text; if (!Error) //Ha hiba volt ne próbáljunk írni { SW.WriteLine(line); //Kiírás fájlba SW.Flush(); //Flush ha hiba lenne } Console.WriteLine(line); //Kiírás konzolba } catch (Exception e) //Ha gond van zárjuk le a fájlt { Error = true; //Hiba történt Add("Log error: " + e.Message); //Ez csak a konzolba ír (Error == true) Close(); } } } publiceventEventHandler Closing; //Eseménylezáráskor publicvoid Close() //Fájllezárása { if (!Closed) //Ha mégnemzártuk le { Add("Log closed."); Closed = true; SW.Close(); //Erőforrások felszabadítása, meghívja a Dispose-t is if (Closing != null) Closing(this, null);//Eseménykezelő hívása } } } BackUpTools (+)
Könyvtárfa másoló algoritmus //Könyvtárfa másolás srcPath-bóldstPath-ba a fileFilter fájlszűrő alkalmazásával publicstaticvoidTreeCopy(stringsrcPath, stringdstPath, stringfileFilter) { Queue<string> dirsToCopy = newQueue<string>(); //A másolandó könyvtárak sora dirsToCopy.Enqueue(srcPath); //A kiinduló könyvtár elhelyezése a listában //Perjel adása az elérési út végéhez, ha nincs if (dstPath[dstPath.Length - 1] != '\\') dstPath += '\\'; string path, relPath; //A teljesés a relatívelérésiút string[] files, dirs; //Az adott mappában található fájlok és könyvtárak //Az eredeti elérési út hossza; mivel minden könyvtár és fájl ez alatt van, //ezért azok elérési útjának ezen a hosszon túlnyúló része adja a relatív elérési utat. intsourcePathLength = srcPath.Length; while (dirsToCopy.Count > 0) //Amíg van mit másolni { path = dirsToCopy.Dequeue(); //Elem kiolvasása a sorból relPath = path.Remove(0, sourcePathLength); //Relatív elérési út számítása if (!Directory.Exists(dstPath + relPath)) //Ha a cél útvonal még nem létezik { try//akkor megpróbáljuk létrehozni { Directory.CreateDirectory(dstPath + relPath); } catch { log.Add("Creation of directory \"" + dstPath + relPath + "\" was unsuccessful."); } } … BackUpTools (+) //Az osztály tesztelésekor ne feledkezzünk meg, egy Log típusú //log változó deklarálásáról az osztályban. //Ennek inicializációja: log = Log.FromFile("log.txt", Encoding.UTF8); //És lezárása: log.Close();
Könyvtárfa másoló algoritmus … try { //Az adott könyvtárban található fájlok lekérdezése files = Directory.GetFiles(path, fileFilter); log.Add("Directory opened: " + (relPath == "" ? path : relPath)); for (int i = 0; i < files.Length; i++) { try//Lemásoljuk a fájlokat { //DifferentialCopy(files[i], dstPath + files[i].Remove(0, sourcePathLength)); File.Copy(files[i], dstPath + files[i].Remove(0, sourcePathLength)); } catch { log.Add("Cannot copy file at " + files[i]); } } //Az adott könyvtárban található könyvtárak lekérdezése dirs = Directory.GetDirectories(path); for (int i = 0; i < dirs.Length; i++) { //Hozzáadás a másolandó listához dirsToCopy.Enqueue(dirs[i]); } } catch { log.Add("Cannot read directory at " + path); } } } BackUpTools (+)
Differenciális fájlmásolás //Differenciális fájmásolás (srcFile: forrásfájl, dstFile: célfájl) //Csak akkor másol, ha a célfájl nem létezik, //vagy létezik, de régebbi, mint a forrásfájl publicstaticvoidDifferentialCopy(stringsrcFile, stringdstFile) { if (!File.Exists(dstFile) || File.GetLastWriteTimeUtc(srcFile) > File.GetLastWriteTimeUtc(dstFile)) { File.Copy(srcFile, dstFile); //ProgressCopy(srcFile, dstFile); log.Add("File backed up: " + Path.GetFileName(srcFile)); } else { log.Add("File skipped: " + Path.GetFileName(srcFile)); } } BackUpTools (+)
//A BackUpTools főprogramja, //parancsori paraméterként megadandó a feladatfájl staticvoid Main(string[] args) { //Naplófájl létrehozása log = Log.FromFile("log.txt", Encoding.UTF8); if (args.Length == 0) //Ha nincs megadva feladatfájl { log.Add("You must specify an input file!"); } else { stringpath = args[0]; //Ha az elérési út relatív, abszolút út meghatározása if (!Path.IsPathRooted(path)) { path = Directory.GetCurrentDirectory() + '\\' + path; } if (File.Exists(path)) { log.Add("Back upstarted..."); //Feladat fájl beolvasása StreamReader SR = newStreamReader(args[0], Encoding.UTF8); string[] line; //Amíg nem vagyunk a fájl végén while (!SR.EndOfStream) { //Sorok feldarabolása paraméterekké a "|" (bar) karakterrel //Feladat fájl felépítése: forrásKönyvtár|célKönyvtár|FájlSzűrő line = SR.ReadLine().Split('|'); if (line.Length == 3) { //Könyvtárfa másolása TreeCopy(line[0], line[1], line[2]); } } log.Add("Back upcomplete."); } else { log.Add("The file \"" + path + "\" cannot be found."); } } log.Close(); //Napló lezárása Console.ReadLine(); } Főprogram BackUpTools (+)
Futási argumentumok megadása BackUpTools (+)
Feladat fájl • A feladat fájl mintája: • Elhelyezése az előző dia argumentuma szerint: • \BackUpTools\BackUpTools\bin\Debug • Tipp: • Projektkönyvtár megnyitása legegyszerűbb, ha a SolutionExplorer-bena projektnévre jobb gombbal kattintva a helyi menüből kiválasztjuk az Open Folderin Windows Explorer menüpontot. F:\Axodox\Dokumentumok\Visual Studio 2008\Projects\Minesweeper|E:\BackUp\Minesweeper|*.* F:\Axodox\Dokumentumok\Visual Studio 2008\Projects\DeepView|E:\BackUp\DeepView|*.* H:\Sintel.2010.2K.SURROUND.x264-VODO|E:\BackUp|*.mp4 BackUpTools (+)
Fájlkezelő dialógusok • A .Net lehetőséget ad a Windows részét képező fájl megnyitó / mentő és mappaválasztó dialógusainak használata. • Ezen elemeket ablaktervező módban is létrehozhatjuk, jellegükből fakadóan azonban nem az ablakon foglalnak helyet. A tervező nézetben az ablak alatt egy elkülönített sávban jelennek meg. • Ezen dialógusok használata igen előnyös, hiszen egyrészt a felhasználók a már jól ismert kezelőfelületen dolgozhatnak, másrészt pedig számos funkciót kellene implementálni hiányukban.
A fájlmegnyitás dialógus • System.Windows.Forms.OpenFileDialog • Fő mezői és metódusai: • DialogResultShowDialog(): a dialógus megjelenítése, ha a visszatérési érték DialogResult.OK, akkor a felhasználó az OK gombra kattintva zárta be az ablakot. • stringFileName { get; set; }: a kiválasztott fájl elérési útja • stringTitle { get; set; }: az ablak fejlécének szövege • stringFilter { get; set; }: fájl típusok felsorolása a „Szöveg fájlok (*.txt)|*.txt|Képek|*.png;*.bmp;*.jpg” formában • intFilterIndex { get; set; }: a kiválasztott szűrő sorszáma 0-tól • boolCheckFileExists { get; set; }: csak létező fájlt lehessen megadni • boolCheckPathExists { get; set; }: csak létező elérési út adható meg • stringDefaultExt { get; set; }: szokásos kiterjesztés, ha a felhasználó nem adja meg, akkor ez hozzáfűződik a fájlnévhez • stringInitialDirectory { get; set; }: kiinduló elérési út • boolMultiselect { get; set; }: több fájl kijelölhetősége • string[] FileNames { get; }: a fájlok eléri útja (több fájl kijelölése esetén) • voidDispose(): az erőforrások felszabadítása
A fájlmentés dialógus • System.Windows.Forms.SaveFileDialog • Fő mezői és metódusai: • DialogResultShowDialog(): a dialógus megjelenítése, ha a visszatérési érték DialogResult.OK, akkor a felhasználó az OK gombra kattintva zárta be az ablakot. • stringFileName { get; set; }: a kiválasztott fájl elérési útja • stringTitle { get; set; }: az ablak fejlécének szövege • stringFilter { get; set; }: fájl típusok felsorolása a „Szöveg fájlok (*.txt)|*.txt|Képek|*.png;*.bmp;*.jpg” formában • intFilterIndex { get; set; }: a kiválasztott szűrő sorszáma 0-tól • boolCheckFileExists { get; set; }: csak létező fájlt lehessen megadni • boolCheckPathExists { get; set; }: csak létező elérési út adható meg • boolOverwritePrompt { get; set; }: rákérdezés a felülírásra • stringDefaultExt { get; set; }: szokásos kiterjesztés, ha a felhasználó nem adja meg, akkor ez hozzáfűződik a fájlnévhez • stringInitialDirectory { get; set; }: kiinduló elérési út • voidDispose(): az erőforrások felszabadítása
A könyvtárválasztó dialógus • System.Windows.Forms.FolderBrowserDialog • Fő mezői és metódusai: • DialogResultShowDialog (): a dialógus megjelenítése, ha a visszatérési érték DialogResult.OK, akkor a felhasználó az OK gombra kattintva zárta be az ablakot. • stringSelectedPath { get; set; }: a kiválasztott könyvtár eléri útja • boolShowNewFolderButton { get; set; }: az új könyvtár gomb megjelenítése • stringDescription { get; set; }: szöveg a könyvtárválasztó ablakrész felett • Environment.SpecialFolder RootFolder { get; set; }: kiinduló rendszerkönyvtár (pl.: Dokumentumok, Képek, lásd az System.Environment.SpecialFolder enumerációt) • voidDispose(): az erőforrások felszabadítása
Feladat • Középiskolás ismerőse MSN-en meséli, hogy irodalomórán olyan feladatot kaptak, hogy keressenek ki fontos motívumokat Petőfi Sándor költészetéből, ezért nem ér rá tovább chatelni, mert könyvtárba kell mennie. • Önnek eszébe jut, hogy Petőfi Sándor összes költeménye megtalálható a magyar elektronikus könyvtárban is, így el is küldi neki a megfelelő txt fájlt. • Közben eszébe jut, hogy könnyen írhatna olyan programot, mely megkeresi a leggyakoribb kifejezéseket a szövegben. • Röviden: írjon programot, mely egy txt fájlt beolvasva megkeresi az abban leggyakrabban előforduló kifejezéseket. Petofi (+)
Kezelőfelület • Helyezzen el egy fájlmegnyitó ablakot (OpenFileDialog) is! • Name: OFD • Filter: Szöveges fájlok (*.txt)|*.txt • Title: Válasszon egy szövegfájlt MainFrom BOpen LBData Petofi (+)
Petőfi 1. using System; usingSystem.Collections.Generic; usingSystem.ComponentModel; usingSystem.Text; usingSystem.Windows.Forms; usingSystem.IO; namespacePetofi { publicpartialclassMainForm : Form { //A szövegösszehasonlító osztály //a szavak gyakorisága szerinti csökkenő sorrendbe rendezéshez classWordComparer : IComparer<KeyValuePair<string, int>> { publicint Compare(KeyValuePair<string, int> x, KeyValuePair<string, int> y) { if (x.Value == y.Value) return 0; if (x.Value > y.Value) return -1; elsereturn 1; } } WordComparer WC; //Konstruktor publicMainForm() { InitializeComponent(); WC = newWordComparer(); } Petofi (+)
Petőfi 2. //A fájlválasztás gomb eseménykezelője privatevoidBBrowse_Click(object sender, EventArgs e) { //Ha a felhasználó OK-kal zárta a dialógust if (OFD.ShowDialog() == DialogResult.OK) { LBData.Items.Clear(); //Az eredménylista ürítése //Szótár a szavaknak Dictionary<string, int> Words = newDictionary<string, int>(); //Szöveg olvasása fájlból StreamReader SR = newStreamReader(OFD.FileName,Encoding.UTF7); string line; //egy sor szöveg string[] lineWords; //egy sor szavai while (!SR.EndOfStream) //amíg nem érünk végig a fájlon { //Kisbetűssé alakítás line = SR.ReadLine().ToLower(); //Feldarabolás szavakká lineWords = line.Split(newchar[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < lineWords.Length; i++) { //Írásjelek eltávolítása lineWords[i] = lineWords[i].Trim(newchar[] { ',', '.', ';', '!', '?' }); if (Words.ContainsKey(lineWords[i])) { //Ha benne van a szótárban növeljük, //hogy hányszor szerpelt eddig Words[lineWords[i]]++; } else { //Ha nincs a szótárban hozzáadjuk Words.Add(lineWords[i], 1); } } } … Petofi (+)
Petőfi 3. … //A lista hossza max 400 szó intlistLength = (Words.Count < 400 ? Words.Count : 400); //Mivel szótárat nem lehet sorbarakni, //mivel abban az elemek sorrendje nem értelmezett, //ezért csinálunk egy listát a rendezéshez List<KeyValuePair<string, int>> wordList = newList<KeyValuePair<string, int>>(Words.Count); wordList.AddRange(Words); //Szavak hozzáadása wordList.Sort(WC); //Rendezés //Mivel sok elemet adunk a listához, kikapcsoljuk az újrarajzolást LBData.SuspendLayout(); for (int i = 0; i < listLength; i++) { //Eredmények megjelenítése LBData.Items.Add(string.Format("{0}. {1} ({2})", newobject[] { (i + 1), wordList[i].Key, wordList[i].Value })); } //Visszakapcsoljuk a lista újrarajzolását LBData.ResumeLayout(); } } } } Petofi (+)
Bináris fájlkezelés • Bináris fájlkezelésről, akkor beszélünk, ha a fájlok tartalmát egy byte-tömbként kezeljük. • Ez nyilvánvalóan csak akkor célszerű, ha adatainkat byte tömb formában is fel tudjuk írni. • Bár a számítógép nyilvánvalóan így tárolja a memóriában a változók értékét, ezeket .Net-ben közvetlenül csak a BitConverter osztállyal, konvertáló parancsokkal, esetleg unsafecontext-ben mutatókkal érhetjük el. • Erre azonban nincs szükség a BinaryReader ill. a BinaryWriter osztály használatakor.
Ismétlés: A BitConverter osztály • A System.BitConverter statikus osztály biztosítja adatok byte tömbbé alakítását (oda-vissza). • ToBoolean/ ToChar/ ToDouble/ ToInt16 (short) / ToInt32 (int) / ToInt64 (long) / ToSingle (float) / ToString / ToUInt16 (usort) / ToUInt32 (uint) / ToUInt64 (ulong): konvertálás adott adattípusba • pl.: intToInt32 ( byte[] value, intstartIndex ): a „value” tömbből a „startindex”-től kiolvas az adattípusnak megfelelő 4 bájtot és integerként visszaadja
Ismétlés: Átalakítás bináris formátumba • byte[]GetBytes ( bool / char / short / int / long / single / double / ushort / uint / ulongvalue ): visszaadja a „value” változó értékét byte-tömb formájában • A visszaadott tömb hossza nyilván az adattípustól függ. (1 byte: bool; 2 byte: char (UTF-16!), short, ushort; 4 byte: int, uint, single; 8 byte: double, long, ulong) • Stringet a System.Text.Encoding osztály elemeivel konvertálunk. • Ez a módszer akkor célszerű adatfolyamba íráskor / olvasáskor, ha csak néhány elemet írunk / olvasunk, különben a BinaryReader / BinaryWriter osztályt érdemes használni.
Egyszerű fájlba író/fájlból olvasó parancsok a File osztályból • voidWriteAllBytes(string path,byte[] bytes): egy byte tömb kiírása fájlba, felülír ha már létezik • byte[]ReadAllBytes(stringpath): teljes fájl beolvasása byte tömbbe
A FileStream osztály • A fájlok bináris elérését a System.IO.FileStream osztály biztosítja. • Segítségével fájlok írása és olvasása is egyszerűen megvalósítható. • Bár itt nem foglalkozunk vele, érdemes kiemelni a System.IO.MemoryStream osztályt, amely kontruktorát leszámítva megegyezik ezzel az osztállyal, de az adatokat a memóriában tárolja, ez sok esetben lehet hasznos (pl.: pufferelés gyorsabb eléréshez). • Ezért célszerű lehet egyes függvényeinket a System.IO.Stream osztályra megírni, mivel az előbbi osztály is ebből származik, így univerzálisabban használható függvényeket kapunk.
Fájlok megnyitása • FileStream ( string path, FileMode mode, FileAccess access): konstruktor, ahol: • path: a fájl elérési útja • mode: a fájl megnyitásának módja (lásd később) • access: a fájl használatának módja (lásd később)