You are on page 1of 15

1.

Suportul pentru directoare i fiiere


La fel ca i limbajul C (revezi cursul de C), n C# salvarea i restaurarea datelor din fiiere implic noiunea de stream. Un stream este o reprezentare abstract a unui dispozitiv serial. Prin utilizarea acestui mecanism, programatorul nu este nevoit s cunoasc structura hardware a echipamentului care stocheaz datele, accesul fiind fcut la nivel logic, prin intermediul fiierelor. Scrierea i citirea datelor din fiiere se face n mod secvenial, putnd fi citii i scrii fie octei, fie caractere. Citirea datelor se face prin intermediul unui stream de intrare. Cel mai des utilizat stream de intrare este tastatura. Dar mecanismul poate fi aplicat i altor echipamente periferice, sau fiierelor obinuite. Scrierea datelor se face prin intermediul unui stream de ieire. S ne reamintim ca streamul standard de ieire este videoterminalul, dar pot fi definite i alte echipamente ca streamuri de ieire, sau pur i simpli fiiere. 1.1 Clase pentru operaii intrare-ieire Toate clasele implicate n transferul i stocarea datelor n fiiere sunt definite n spaiul de nume System.IO. Pentru a putea utiliza aceste clase, va trebui s specificm la nceputul fiierului surs n care se declar clasele de lucru utilizarea acestui spaiu (dac nu exist) prin directiva
using System.IO;

Exist mai multe clase coninute n acest spaiu de nume, clase care ne permit s manipulm att fiiere ct i directoare. Cteva din aceste clase sunt: File este o clas care expune un set de metode statice (s ne reamintim, o metod static este apelat prin intermediul clasei i nu a unui obiect din clasa respectiv, fiind un atribut al clasei) pentru crearea, deschiderea, copierea, mutarea sau tergerea fiierelor. Directory - este o clas care expune un set de metode statice pentru crearea, deschiderea, copierea, mutarea sau tergerea directoarelor. Path este o clas care expune metode de manipulare a cilor de directoare. FileInfo este o clas a crei obiecte reprezint fiiere fizice pe disc i expune metode de manipulare a ecestor fiiere. Pentru operaii de scriere-citire asupra acestor fiiere va trebui creat un obiect Stream. DirectoryInfo - este o clas a crei obiecte reprezint directoare fizice pe disc i expune metode de manipulare a ecestor directoare. FileStream un obiect al acestei clase reprezint un fiier care poate fi scris, citit sau scris i citit. StreamReader obiectele acestei clase sunt utilizate pentru citirea unui stream dintr-un fiier de tip FileStream. StreamWriter - obiectele acestei clase sunt utilizate pentruscrierea unui stream ntr-un fiier de tip FileStream Aparent, clasele File i FileInfo, respectiv Directory i DirectoryInfo expun metode similare. Poate apare ntrebarea care din clase este mai bine s fie folosite.

n realitate metodele nu sunt chiar identice, iar pentru cele care sunt, alegerea rmne la latitudinea programatorului. 1.2 Clasele File i Directory Aa cum am artat mai sus, sunt clase care expun un set de metode statice pentru manipularea fiierelor i directoarelor. Prin intermediul lor, fiierele i directoarele pot fi manipulate fr a crea instane ale acestor clase. Cteva metode mai des utilizate ar fi: File
public static FileStream Create (String path) creaz un fiier cu numele specificat n variabila path. Returneaz un obiect FileStream, care poate fi

utilizat pentru scrierea-citirea datelor la nivelul fiierului.


public static FileStream Open (String path,FileMode mode) deschide un fiier specificat de calea path n modul descris de mode. Returneaz obiectul FileStream pentru manipularea datelor. Enumerarea FileMode specifica modul de

deschidere al fiierului. Membrii acestei enumerri sunt (fr a mai preciza semnificaia lor, fiind foarte semntori cu ce ai nvat n cursul de C): Append, Create, CreateNew, Open, OpenOrCreate, Truncate. public static void Delete (string path) terge fiierul cu numele specificat de variabila path. public static void Copy (String sourceFileName,String destFileName) copiaz fiierul cu numele sourceFileName n fiierul cu numele destFileName. Ca o obsrevaie, acesta din urm nu trebuie s existe, pentru c la copiere este creat automat.
public static void Move (String sourceFileName,String destFileName)

mut fiierul surs n destinaie.


public static bool Exists (string path) - returneaz true dac fiierul

specificat exist. Directory


public static DirectoryInfo CreateDirectory (String path) creaz directorul cu numele specificat de variabila path. Returneaz un obiect

DirectoryInfo care reprezint chiar acel director. Despre clasa DirectoryInfo vom vorbi mai jos. public static void Delete (String path) terge directorul cu numele specificat de variabila path. Acest director trebuie s fie gol n momentul tergerii. public static string GetCurrentDirectory () returneaz calea spre directorul curent. public static void SetCurrentDirectory (String path) seteaz directorul curent la calea path.
public static String[] GetDirectories (String path) returneaz un ir de nume de directoare, reprezentnd subdirectoarele directorului cu numele conimut n variabila path. public static string[] GetFiles (String path) returneaz numele fiierelor.

public static bool Exists (string path) returneaz true dac directorul

specificat exist.
public static void Move (String sourceDirName,String destDirName) mut directorul sourceDirName la calea destDirName.

Toate metodele n caz de eroare arunc un set de excepii. Le vom detalia n momentul implementrii unui exemplu. 1.3 Clasele FileInfo i DirectoryInfo Spre deosebire de clasele anterioare, aceste clase nu expun metode statice. Metodele expuse de acestea pot fi utilizate doar prin intermediul unor obiecte ale claselor. Un obiect FileInfo reprezint un fiier fizic pe disc. El nu este un stream! Pentru manipularea datelor acestuia, va trebui creat i asociat un obiect FileStream. Implementarea acestui mecnism o vom descrie mai trziu. Construcia unui obiect FileInfo se face prin specificarea pentru constructorul clasei a cii i numelui fiierului asociat. n exemplul de mai jos, se creeaz fsierul C:/postuniv.exemplu.txt.
FileInfo fisier=new FileInfo(C:/postuniv.exemplu.txt);

Pe lng metodele expuse, n mare parte asemntoare cu metodele clasei File, clasa FileInfo expune i un set de proprieti utile pentru menipularea fiierelor. Cteva din acestea sunt: Attributes conine atributele fiierului asociat. CreationTime conine data i ora crerii fiierului asociat. DirectoryName numele directorului n care se gsete fiierul. Exists true dac fiierul cu numele specificat exist. FullName numele complet (cale+nume) pentru fiier. Length lungimea fiierului. Name numele (fr cale) fiierului. Clasa DirectoryInfo expune n mare parte aceleai metode i proprieti ca i clasa FileInfo. 1.4 Obiecte FileStream Clasa FileStream implementeaz obiecte care reprezint fiiere pe disc. Este utilizat n general pentru a manipula adte de tip octet. Pentru manipularea datelor de tip caracter, este mai simplu s se utilizeze alte 2 clase, respectiv StreamReader i StreamWriter. Exist mai multe ci prin care se poate crea un obiect FileStream. Cea mai simpl metd este de a preciza constructorului clasei numele fiierului asociat i modul de deschider a fiierului:

FileStream fs=new FileStream(fis.txt, FileMode.OpenOrCreate);

n acest caz, obiectului fs i este asociat fiierul fis.txt, care este deschis dac exist, respectiv creat dac nu exist. Enumerarea FileMode ofer mai multe moduri de deschidere a unui fiier: Append deschide sau creeaz un fiier, fr s tearg datele existente. Datele nou introduse se adaug la sfeitul fiierului. Fiierul trebuie s fie deschis n scriere. Create creaz un nou fiier gol. Dac el deja exist, datele coninute se pierd. CreateNew creeaz un nou fiier. Dac un fiier cu numele specificat exist, se genereaz o excepie. Open deschide un fiier existent. Dac acesta nu exist, se genereaz o excepie. OpenOrCreate deschide un fiier existent, sau, dac nu exist, l creaz.

Elementele FileMode se pot utiliza n conjuncie cu elemente din enumerarea FileAccess, care precizeaz modul de acces la datele fiierului. Acestea sunt: Read fiierul este deschis n citire. Write fiierul este deschis n scriere. ReadWrite fiierul este deschid n scriere i citire. Deci, o alt form de creare a unui obiect FileStream este
FileStream fs=new FileStream(fis.txt,FileMode.Open, FileAccess.Write);

De altfel, i clasele File i FileInfo expun metode de deschidere a unui fiier:


OpenRead(), respectiv OpenWrite(). Deci, construcia unui obiect FileStream poate

fi fcut i n unul din modurile de ma jos:


FileStream fs=File.OpenRead(fis.txt);

sau
FileInfo fi=new FileInfo(fis.txt); FileStream fs=fi.OpenRead();

1.4.1 Poziionarea ntr-un fiier Metoda clasei FileStream care permite poziionarea n interiorul unui fiier este
public long Seek(long offset, SeekOrigin origin)

Parametrul offset specific numrul de octei peste care se face saltul, iar parametrul origin specific originea saltului. Enumerarea SeekOrigin are urmtoarele elemente: Begin saltul se face cu offset octei, numrai de la nceputul fiierului.

Current - saltul se face cu offset octei, numrai de la poziia curent n fiier.. End - saltul se napoi face cu offset octei, numrai de la sfritul fiierului.

Din momentul apelului metodei, noua poziie devine poziie curent n fiier. Saltul n afara fiierului genereaz excepie. Cteva exemple de utilizare ar fi:
FileStream fi=File.OpenRead(fis.dat); fi.Seek(12,SeekOrigin.Begin);

Poziia curent n fiier este octetul al 12-lea, numrat de la nceputul fiierului.


fi.Seek(10,SeekOrigin.Current);

Se face un salt de 10 octei fa de poziia curent.


fi.Seek(-8,SeekOrigin.End);

Poziia curent n fiier este cu 5 octei nainte de sfritul fiierului. Evident, orice operaie de citire-scriere ulterioar se va face de la noua poziie curent n fiier. 1.4.2 Citirea i scrierea datelor din fiier Clasa FileStream furnizeaz i metode de scriere-citire. Le vom prezenta, dar nu vom intra n amnunte, deaorece marea majoritate a operaiilor intrare-ieire se realizeaz cu ajutorul claselor StreamReader i StreamWriter. Citirea octeilor dintr-un fiier se face cu metoda
public int Read(byte[] array, int offset, int count)

Primul paramtru este numele unui ir de octei n care se vor stoca octeii citii din fiier. Al doilea parametru specific poziia n ir ncepnd cu care se vor depune octeii, iar al treilea ci octei vor fi citii. n caz de eroare, metoda genereaz excepie. De exemplu secvena:
byte[] data=new byte[100]; try { FileStream fi=new FilStream(fis.dat,FileMode.Open); fi.Seek(20,SeekOrigin.Begin); fi.Read(data,40,10); } catch(Exception ex) { MessageBox.Show(ex.Message); }

va citi 10 octei din fiier, ncepnd cu poziia 20 i i va stoca n irul data ncepnd cu indexul 40. Similar, scrierea de octei n fiier se face cu ajutorul metodei
public int Write(byte[] array, int offset, int count)

Exemplul
byte[] data=new byte[100]; for (int i=0;i<30;i++) data[i]=i; try { FileStream fi=new FilStream(fis.dat,FileMode.OpenOrCreate); fi.Seek(0,SeekOrigin.Begin); fi.Write(data,0,30); } catch(Exception ex) { MessageBox.Show(ex.Message); }

va scrie primii 30 de octei din irul data n fiier, ncepnd cu poziia 0. 1.5 Clasele StreamReader i StreamWriter Atunci cnd avem de transferat caracter, clasele StreamReader i StreamWriter ofer o modalitate mult mai elegant de lucru. Clasa StreamReader permite citirea irurilor de caracter dintr-un fiier, iar clasa StreamWriter scrierea irurilor de caractere. Metodele acestot clase permit manipularea de obiecte String, cu toate eventajele care decurg din aceasta. Modalitatea de construcie a obiectelor StreamReader i StreamWriter este foarte simpl: fie se construiete un obiect FileStream i noul obiect StreamReader sau StreamWriter se asociaz acestuia, sau pur i simplu obiectele sunt construite prin furnizarea ctre constructor a numelui fiierului. Secvena
FileStream fi=new FileStream(fis.txt, FileMode.Create); StreamWriter sw=new StreamWriter(fi); sw.WriteLine( Salut!); sw.Write(Putem inchide); sw.Close();

va crea un obiect StreamWriter asociat fiierului fis.txt nou creat i va scrie cele 2 texte, n primul caz trecnd pe linie nou dup scrierea textului. O secven similar, poate fi
StreamWriter sw=new StreamWriter(fis.txt,false); sw.WriteLine( Salut!); sw.Write(Putem inchide); sw.Close();

Efectul este acelai, dar constructorului clasei StreamWriter i se transmite direct numele fiierului i true dac ca datele s fie adugate n fiier, respectiv false dac fiierul se creeaz gol. Deci
StreamWriter sw=new StreamWriter(fis.txt,false);

este echivalent cu
FileStream fi=new FileStream(fis.txt, FileMode.Create); StreamWriter sw=new StreamWriter(fi);

respectiv
StreamWriter sw=new StreamWriter(fis.txt,true);

cu
FileStream fi=new FileStream(fis.txt, FileMode.Append); StreamWriter sw=new StreamWriter(fi);

Obiectele StreamReader funcioneaz de o manier similar:


String sir; FileStream fi=new FileStream(fis.txt, FileMode.Open); StreamReader sr=new StreamReader(fi); sir=sr.ReadLine(); sr.Close();

va citi o linie din fiierul fis.txt i o va salva n stringul sir.


String sir, temp; StreamReader sr=new StreamReader(fis.txt); temp=sr.ReadLine(); while ( temp!=null) { sir+=temp; temp=sr.ReadLine(); } sr.Close();

n secvena de mai sus, se poate observa modalitatea de construcie a obiectului StreamReader prin transmiterea direct ctre constructor a numelui fiierului. Secvena citete toate liniile din fiier (cnd se ajunge la sfritul fiierului ReadLine() returneaz null) i le salveaz n irul sir. S construim un exemplu. Pentru aceasta s crem un nou proiect de tip WindowsApplication, pe care haidei s-l numim unu. S construim apoi machete din fig. 1.1. Prin intermediul acestei aplicaii, vom realize citirea, editarea i salvarea coninutului fiierelor cu extensia .txt . Macheta conine un control TextBox i 3 controale Button. Pentru controlul TextBox, s modificm proprietatea Name la eFis proprietatea Multiline la True (permind astfel inserarea mai multor linii n control) i proprietatea ScrollBars la Both (am adugat astfel n caz de necesitate bare de

scroll orizntal i vertical). De asemenea, pentru controalele Button, s modificm proprietile Name i Text n felul urmtor (de la stnga la dreapta): open respectiv Open, save respectiv Save i exit respectiv Exit.

Figura 1.1

Evident, apsarea butonului Open va permite alegerea i deschiderea unui fiier, iar butonul Save salvarea acestuia. Dorim s implementm mecanismul de deschidere-salvare standard n sistemul de operare Windows. Pentru aceasta, infrastructura ne pune la dispoziie 2 clase, OpenFileDialog i respective SaveFileDialog, care permit menipularea fiierelor prin intermediul unor controale de dialog. 1.5.1 OpenFileDialog Infrastructura C# ofer casete de dialog pentru manipularea numelor de fiiere. O astfel de caset este OpenFileDialog (fig. 1.2).

Figura 1.2

Figura 1.3

n aceast caset se poate cuta numele unui fiier existent sau aduga un nou nume. De aseemenea, se permite specificarea tipului de fiier care urmeaz s fie ncrcat. Pentru specificarea tipurilor de fiiere acceptate, trebuie construit un filtru, dup urmtorul mecanism:
mesaj1 | tip1 fiier | mesaj2 | tip2 fisier | | mesajn | tipn fiier ;

Acest filtru trebuie aplicat casetei de dialog dup creare cu instruciunea new, dar nainte de afiare cu funcia ShowDialog(). Permite utilizarea aa numitelor wildcards (semnele ? , respectiv *). Caseta de dialog ofer o serie de proprieti utile pentru utilizator. Cteva din acestea sunt: Title permite modificarea textului afiat n bara de titlu a casetei de dialog; FileName numele fiierului (fiierelor) selectate; InitialDirectory numele directorului n care ncepe cutarea 1.5.2 SaveFileDialog n figura 1.3 este prezentat caseta de dialog SaveFileDialog. Aceasta permite salvarea cu un nume ales sau dat a unui fiier. Modul de lucru cu aceast caset de dialog este absolut similar casetei OpenFileDialog. Deoarece fiierele sunt entiti externe programului, ncercarea de accesare a unui fiier cu nume eronat poate duce la erori n cadrul programului, respectiv la oprirea lui forat de ctre sistemul de operare. De aceea, nainte de a implementa funcia care se execut la apsarea butonului Open, mai trebuie s vorbim despre 1.5.3 Excepii Complexitatea aplicaiilor actuale, n special a celor orientate pe obiecte, presupune o modularizare pe nivele ierarhice. Aceast situaie impune tratarea deosebit de riguroas a situaiilor deosebite, n special a erorilor care pot s apar la nivelul diferitelor componente ale unui proiect. n cele ce urmeaz, vom nelege prin excepie o situaie deosebit care poate s apar pe parcursul execuiei unei componente soft parte a unei aplicaii. Erorile pot fi privite ca i un caz particular de excepii, dar n general nu toate excepiile sunt erori. Excepiile se mpart n dou categorii: excepii sincrone i excepii asincrone. Excepiile sincrone sunt excepii a cror apariie poate fi prevzut de programator (de exemplu, un fiier care se dorete a fi prelucrat nu se afl n directorul ateptat). Excepiile asincrone sunt excepii a cror apariie nu poate fi prevzut n momentul implementrii programului (de exemplu, defectarea accidental a hard-disk-ului). Mecanismul de tratare a excepiilor ia n considerare numai situaia excepiilor sincrone. Problema se pune astfel: n faza de programare, se poate presupune c un modul de program va detecta n anumite situaii o excepie, dar nu va putea oferi o soluie general de tratare a acesteia, n timp ce un alt modul al aplicaiei poate oferi o soluie de tratare a excepiei, dar nu poate detecta singur apariia excepiilor. Exemple tipice de excepii: mprire cu 0, accesul la un fiier inexistent, operaii cu o unitate logic nefuncional, etc. Uzual, la pariia unei excepii, sistemul de operare va opri forat execuia modului de program n care excepia s-a produs, pentru ca acesta s nu afecteze buna funcionare a celorlalte programe. De multe ori ns este necesar ca excepia aprut s nu fie transmis sistemului de operare, ci s fie prins i tratat n interiorul modulului care a generat-o. Acest lucru este posibil prin intermediul unui mecanism bazat pe 2 instruciuni: try i catch.

Mecanismul este urmtorul: zona critic, adic zona de cod n care programatorul prevede posibilitatea apariiei unei excepii este scris ntr-un bloc try. Blocul try este urmat de unul su mai multe blocuri catch, cte unul pentru fiecare tip de execepie ce poate s apar. Execuia programelor n acest caz este prezentat n fig. 1.4 a i b.
try { Seciune critic try { excepie

} catch ( TipExceptie e) { }

} catch ( TipExceptie e) { }

a Figura 1.4

Fig. 1.4a prezint situaia normal de execuie, cnd n seciunea critic nu apare excepie. n acest caz, se execut n succesiune normal toate instruciunile din seciunea critic, dup care, urmtoarea instruciune executat este prima de dup blocul catch, acesta fiind neglijat. Fig. 1.4b prezint situaia apariiei unei excepii. n acest caz, urmtoarea unstruciune executat dup cea care a generat excepia este prima din blocul catch, n acesta urmnd a fi tratat excepia. Dup execuia instruciunilor din blocul catch, se continu n secven normal, cu prima instruciune de dup acesta. Marea majoritate a claselor care lucreaz cu entiti externe memoriei genereaz excepii, pentru ca posibilele erori s poat fi tratate nc din faza de programare. Este i cazul claselor care lucreaz cu fiiere i este indicat ca toate operaiile fcute asupra fiierelor s fie tratate prin mecanismul try-catch. i acum s trecem la implementare. Vom apsa dublu-click pe butonul Open i vom implementa codul:
private void open_Click(object sender, EventArgs e) { eFis.Clear(); OpenFileDialog op = new OpenFileDialog(); op.InitialDirectory = Directory.GetCurrentDirectory(); op.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"; if (op.ShowDialog() == DialogResult.OK) { String strLin; try { StreamReader sr = new StreamReader(op.FileName); strLin = sr.ReadLine(); while (strLin != null) {

10

} catch (Exception ex) { MessageBox.Show(ex.Message); } } }

} sr.Close();

eFis.Text += strLin + "\r\n"; strLin = sr.ReadLine();

Coninutul funciei este foarte uor de neles dac inem cont de cele prezentate anterior. Se terge coninutul controlului TextBox i se creaz un obiect OpenFileDialog, pentru care se definete filtrul i directorul iniial de cutare ca fiind directorul curent. Apoi se afieaz controlul. La revenire din caseta OpenFileDialog, dac s-a revenit apsnd butonul OK, se creeaz un StreamReader asociat fiierului ales n caseta OpenFileDialog (prin transmiterea ctre StreamReader a numelui acestuia) i coninutul fiierului este citit linie cu linie. Fiecare linie citit este adugat proprietii Text a controlului TextBox, dup care se adaug uril CR-LF. De o manier similar se implementeaz i funcia executat la apsarea butonului Save.
private void save_Click(object sender, EventArgs e) { SaveFileDialog sv = new SaveFileDialog(); sv.InitialDirectory = Directory.GetCurrentDirectory(); sv.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"; if (sv.ShowDialog() == DialogResult.OK) { try { StreamWriter sr = new StreamWriter(sv.FileName, false); sr.WriteLine(eFis.Text); sr.Close(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } }

Aceast funcie nu mai necesit explicaii. i n fine, ultima implementare,


private void exit_Click(object sender, EventArgs e) { Application.Exit(); }

Compilai i executai programul.

11

1.6 Serializarea datelor Pn acum am vzut cum se pot salva i restaura n i din fiiere datele de tip octet sau caracter. Dar ce e de fcut, dac avem de salvat i restaurat date mai complexe, de exemplu obiecte ale unei clase? Evident, obiectele se pot salva sub form de iruri de octei, dar va fi foarte greu la restaurare s mprim octeii astfel nct s recompunem obiectele salvate. Din fericire, majoritatea limbajelor de nivel nalt, inclusiv C#, implementeaz un mecnism simplu i fiabil ne salvare i restaurare a obiectelor prin intermediul fiierelor. Acest mecanism poart denumirea de serializare. Orice clas ale crei obiecte pot fi salvate sau restaurate prin intermediul fiierelor, va trebui fie s fie declarat serializabil, fie s implementeze o interfa specific, numit ISerializable. n momentul n care infrastructura primete o cerere de serializare a unor obiecte, va verifica nti dac clasa din care fac parte obiectele implementeaz interfaa ISerializable i dac nu, va verifica dac a fost declarat ca fiind serializabil. Dac nici una din condiii nu este ndeplinit, obiectele nu vor putea fi serializate. Declararea unei clase ca fiind serializabile este foarte simpl. Pur i simplu, clasei i este specificat atributul [Serializable]. S lmurim printr-un exemplu. S crem un nou proiect, fie unu-unu numele acestuia i proiectului s-i adugm o nou clas, numit Rezervare: click dreapta pe rdcina unu-unu n Solution explorer, Add, Class, i la Name scriem Rezervare. S adugm atributele clasei, un constructor i s-o declarm serializabil.
namespace unu_unu { [Serializable] class Rezervare { public Rezervare() { } public String Nume; public DateTime DataS; public DateTime DataP; public int nrCam; } }

Am adugat clasei un constructor, 4 atribute de tip String, DateTime i int. Obiectele clasei pot reprezenta de exemplu rezervri la un hotel, pentru care se specific numele clientului, data sosirii, data plecrii i numrul de camere rezervate. Prin adugarea atributului [Serializable], clasa a fost declarat automat serializabil, deci instanele ei vor putea fi salvate i restaurate din fiiere. S implementm acum interfaa de lucru. Vom impelementa interfaa din

12
Figura 1.5

figura 1.5, pentru care controalele TextBox au urmtoarele atribute Name (de sus n jos i de la stnga la dreapta): nume, zis, ls, ans, zip, lp, anp, respectiv nrc, iar butoanele (de la stnga la dreapta) salvare i restaurare. Transformarea obiectelor n iruri de octei pentru a fi executat transferul la nivelul fiierului, se face utiliznd formatori (Formatters). Exist 2 tipuri de formatori: BinaryFormatter i SoapFormatter. Pe primul l vom folosi aici, pentru a formata obiectele n i din iruri de octei, iar pe al doilea l vom ntlni n capitolele viitoare. Pentru a putea utiliza aceste formatoare, va trebui s adugm fiierului care implementeaz forma spaiul de nume System.Runtime.Serialization.Formatters.Binary, iar pentru a putea implementa mecanismul efectiv de serializare, spaiul de nume System.Runtime.Serialization. S ne reaminim de asemenea, c pentru a putea lucra cu fiiere, va trebui s adugm i spaiul de nume System.IO:
using System; using System.Collections.Generic; using System.Windows.Forms; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; namespace unu_unu { public partial class Form1 : Form {

Vom aduga clasei Form1 un obiect Rezervare, care s fie vizibil n toate metodele clasei:
public partial class Form1 : Form { Rezervare rez = new Rezervare(); public Form1() {

i acum s implementm metodele de srializare i deserializare a obiectelor Rezervare. Vom aduga clasei o metod care realizeaz serializarea, numit Salvare().
public void Salvare() { Stream s = File.Open("rezervare.rez", FileMode.Create); BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(s, rez); s.Close(); MessageBox.Show("Salvat"); this.Close(); }

13

Cum lucreaz metoda? nti creaza un Stream asociat fiierului rezervare.rez pe care-l deschide n mod creare. Creaz apoi un nou obiect de tip BinaryFormatter, prin intermediul cruia apeleaz metoda
public void Serialize (Stream serializationStream,Object graph)

unde serializationStream este stream-ul n care se serializeaz obiectul graph. Cu alte cuvinte, n cazul nostru, obiectul rez de clas Rezervare va fi salva n streamul s, adic n fiierul rezervare.rez. Gata. E simplu, formatorul s-a ocupat singur de serializarea obiectului. S vedem cum arat restaurarea. Vom implementa metoda Refacere():
public void Refacere() { Stream s = File.Open("rezervare.rez", FileMode.Open); BinaryFormatter bf = new BinaryFormatter(); Object obj = bf.Deserialize(s); rez = obj as Rezervare; }

Simplu din nou. Pentru deserializare am folosit metoda (care cred c nu mai necesit explicaii suplimentare)
public Object Deserialize (Stream serializationStream)

Deoarece metoda salveaz obiectul serializat ntr-un obiect generic de clas Object, pe acesta l-am particularizat ulterior la clasa Rezervare. Evident, metoda se poate rescrie cu ajutorul conversiei explicite de tip (cast):
public void Refacere() { Stream s = File.Open("rezervare.rez", FileMode.Open); BinaryFormatter bf = new BinaryFormatter(); rez = (Rezervare)bf.Deserialize(s); }

Ambele modaliti de scriere sunt echivalente. Acum tot ce ne mai rmne de fcut e s implementm funciile care rspund la apsarea butoanelor:
private void salvare_Click(object sender, EventArgs e) { rez.Nume = nume.Text; rez.DataS = Convert.ToDateTime(zis.Text + "." + ls.Text + "." + ans.Text); rez.DataP = Convert.ToDateTime(zip.Text + "." + lp.Text + "." + anp.Text); rez.nrCam = Convert.ToInt16(nrc.Text); Salvare(); }

Nu am fcut altceva dect s completm atributele obiectului rez cu datele din controalele TextBox i s convertim mrimile asociate la tipul DateTime. Dup care am apelat funcia de serializare.

14

private void restaurare_Click(object sender, EventArgs e) { Refacere(); if (rez != null) { nume.Text = rez.Nume; String x; int i1, i2; x = Convert.ToString(rez.DataS); i1 = x.IndexOf('.'); i2 = x.LastIndexOf('.'); zis.Text = x.Substring(0, i1); ls.Text = x.Substring(i1 + 1, i2-i1-1); ans.Text = x.Substring(i2+1, 4); x = Convert.ToString(rez.DataP); i1 = x.IndexOf('.'); i2 = x.LastIndexOf('.'); zip.Text = x.Substring(0, i1); lp.Text = x.Substring(i1 + 1, i2 - i1 - 1); anp.Text = x.Substring(i2 + 1, 4); nrc.Text = Convert.ToString(rez.nrCam); } else MessageBox.Show("Citire nereusita"); }

Ce am fcut? Am deserializat din fiier obiectul rez, dup care componentele lui sunt afiate n controalele TextBox. Deoarece stringul rezultat n urma conversiei din DateTime este de forma zz.ll.aaa, am extras subirurile corespunztoare zilei, lunii i anului, pentru a putea fi afiate. Dac deserializarea a reuit, obiectul rez se ncarc cu datele preluate din fiier. n caz contrar, funcia Deserialize() returneaz null. Compilai i executai programul.

15

You might also like