Sunteți pe pagina 1din 18

Dezvoltarea de interfete utilizator avansate folosind AWT

Ferestre, cadre şi casete de dialog

În afară de ceea ce vi s-a prezentat până acum, AWT mai oferă posibilitatea creării de
elemente de interfaţă în afara suprafeţei applet-ului sau a ferestrei browserului, elemente cum ar fi
ferestre, cadre sau casete de dialog. Aceste facilităţi vă permit să creaţi aplicaţii complete, ca parte a
applet-ului sau ca aplicaţii Java independente.

Clasele Window

Clasele AWT care produc ferestre sau casete de dialog moştenesc o clasă comună, Window.
Clasa Window moşteneşte clasa Container, ca şi componentele panou şi applet, şi oferă un
comportament generic pentru toate elementele derivate din ferestre.
De obicei nu se folosesc instanţe ale clasei Window, ci ale celor două subclase principale
ale sale: Frame şi Dialog.
Clasa Frame (cadru) oferă o fereastră care conţine o bară de titlu, butoane de închidere şi
alte elemente specifice unei ferestre pentru un anumit sistem. De asemenea, cadrele permit
adăugarea unor bare de meniuri. Clasa Dialog este o variantă mai limitată a clasei Frame, care, de
obicei, nu are un titlu. FileDialog, o subclasă a clasei Dialog, oferă o casetă de dialog standard
pentru alegerea unui fişier (de obicei, aceasta poate fi folosită doar în cadrul aplicaţiilor Java,
deoarece applet-urile impun restricţii de securitate).
Pentru a adăuga o fereastră sau o casetă de dialog în applet-ul sau aplicaţia dumneavoastră
trebuie să creaţi subclase ale claselor Frame sau Dialog.

Cadre

Cadrele (frames) sunt ferestre independente de fereastra applet-ului sau a browserului care
conţine applet-ul; ele sunt ferestre separate, care conţin titluri proprii, butoane de redimensionare
sau de închidere şi bare de meniuri. Puteţi crea cadre, în applet-uri, pentru a produce ferestre sau le
puteţi folosi în aplicaţii pentru a păstra conţinutul acestora.
Un cadru reprezintă o fereastră specifică unei anumite platforme, care conţine un titlu, o bară
de meniuri, butoane de închidere şi de redimensionare şi alte elemente specifice unei ferestre.
Pentru a crea un cadru se foloseşte unul din următorii constructori:
 new Frame () creează un cadru simplu, fără titlu.
 new Frame (String) creează un cadru simplu, cu titlul dat de şirul primit ca argument.
Deoarece cadrele moştenesc clasa Window, care moşteneşte clasa Container, care
moşteneşte clasa Component, cadrele sunt create şi folosite cam în acelaşi fel cu celelalte
componente AWT. Cadrele sunt containere, ca şi panourile, deci puteţi adăuga în ele diferite
componente folosind metoda add (), ca şi în panouri (panels). Dispunerea prestabilită pentru cadre
este BorderLayout. Iată un exemplu care creează un cadru, stabileşte dispunerea componentelor în
acesta şi adaugă două butoane:
win = new Frame("Fereastra mea") ;
win.setLayout(new BorderLayout(10, 20));
win.add("North", new Button("Start")) ;
win.add("Center", new Button("Mutare"));
Pentru a stabili dimensiunea noului cadru se foloseşte metoda resize (), care primeşte ca
argumente lăţimea şi înălţimea acesteia. De exemplu, această linie de cod redimensionează fereastra
la dimensiunile de 100 pixeli lăţime şi 200 pixeli înălţime:
win.resize(100, 200);
Deoarece în sisteme diferite se calculează în mod diferit reprezentările pixelilor şi există
rezoluţii diferite, este dificilă crearea unui cadru de dimensiuni „bune" pentru oricare platformă.
Ferestrele care sunt potrivite într-un sistem pot fi prea mici sau prea mari într-un altul.
O metodă de evitare a acestei probleme este folosirea metodei pack() în locul metodei
resize(). Metoda pack(), care nu primeşte argumente, creează o fereastră de cea mai mică
dimensiune posibilă, date fiind dimensiunile curente ale componentelor pe care le conţine,
administratorul de dispunere şi inserţiile folosite. Următorul exemplu creează două butoane şi le
adaugă într-o fereastră. După aceasta, fereastra este adusă la cele mai mici dimensiuni posibile când
conţine aceste două butoane.
FlowLayout flo = new FlowLayout() ;
Button ok = new Button("OK");
Button anulare = new Button("Anulare");
win.setLayout(flo);
win.add(ok) ;
win.add(anulare);
win.pack() ;
Atunci când creaţi o fereastră, aceasta este invizibilă. Pentru a fi afişată pe ecran trebuie să
folosiţi metoda show(). Pentru a o ascunde din nou puteţi folosi metoda hide(). Exemplu:
win.show() ;
Reţineţi că atunci când o fereastră este afişată de un applet, browserul vă atrage atenţia că
aceasta nu este o fereastră a sa, de obicei, printr-un mesaj în cadrul ferestrei.

Casete de dialog

Casetele de dialog, din punct de vedere funcţional, sunt asemănătoare cadrelor prin faptul că
afişează ferestre pe ecran. Totuşi, ele sunt destinate pentru a fi folosite drept ferestre temporare –
adică pentru a vă prezenta mesaje de avertizare, pentru a vă cere anumite informaţii şi aşa mai
departe.
Casetele de dialog nu au, de obicei, bare de titlu sau alte elemente caracteristice unei ferestre
(cu toate că puteţi crea şi casete de dialog cu bare de titlu). Ele pot fi definite aşa încât să nu fie
redimensionabile sau pot fi definite drept modale. (Casetele de dialog modale împiedică accesarea
altor ferestre până în momentul când se renunţă la ele.)
Casetele de dialog sunt ferestre temporare având rolul de a alerta utilizatorul cu privire la un
anumit eveniment sau de a prelua date de la utilizator. Spre deosebire de cadre, casetele de dialog
nu posedă, de obicei, bare de titlu sau butoane de închidere.
O casetă de dialog modală nu permite introducerea de date în alte ferestre până când nu este
închisă. Nu veţi putea aduce în prim plan o altă fereastră şi nici minimiza caseta de dialog modală;
aceasta trebuie închisă explicit pentru a se putea continua lucrul în sistem. De obicei, avertismentele
sunt casete de dialog modale.
AWT oferă două tipuri de casete de dialog: clasa Dialog, care produce o casetă de dialog
generică, şi FileDialog, care produce o casetă de dialog pentru căutarea de fişiere, specifică
platformei respective.
Obiecte dialog

Casetele de dialog se creează şi se folosesc asemănător ferestrelor. Pentru crearea unei


casete de dialog generice se foloseşte unul din următorii constructori:
 Dialog (Frame, boolean) creează o casetă de dialog invizibilă, ataşată cadrului curent, fie
modală (true), fie nemodală (false).
 Dialog(Frame, String, boolean) creează o casetă de dialog invizibilă, cu titlul dat de
argumentul şir, ataşată cadrului curent, modală (true) sau nu (false).
Fereastra de dialog, ca şi cadrul de fereastră (frame), este un panou pe care se pot dispune şi
desena componente de interfaţă sau pe care se pot realiza operaţii grafice, la fel cum s-ar proceda cu
oricare alt panou. Ca şi alte ferestre, şi cea de dialog este iniţial invizibilă, însă o puteţi afişa sau
ascunde folosind metodele show() , respectiv hide().

Ataşarea casetelor de dialog la applet-uri

Casetele de dialog pot fi ataşate numai cadrelor (frames). Pentru a crea o casetă de dialog,
trebuie să transmiteţi o instanţă a clasei Frame uneia dintre metodele constructor ale casetei de
dialog. Acest lucru înseamnă că nu puteţi crea casete de dialog ataşate applet-urilor. Deoarece
applet-urile nu sunt cadre, nu le puteţi transmite ca argument unei clase Dialog. Totuşi, cu puţină
îndemânare, puteţi face rost de un obiect cadru care conţine un applet (adesea, chiar browserul sau
fereastra de vizualizare a applet-ului), după care să folosiţi acest obiect drept cadru pentru caseta de
dialog.
Codul care face acest lucru foloseşte metoda getParent(), definită pentru toate
componentele AWT. Metoda getParent() returnează obiectul care conţine obiectul curent. Deci
părintele tuturor aplicaţiilor AWT trebuie să fie un cadru. Applet-urile se comportă în acelaşi mod.
Prin apelarea în mod repetat a metodei getParent() veţi ajunge, până la urmă, să obţineţi o instanţă
a clasei Frame. lată codul pe care trebuie să îl introduceţi în applet-ul dumneavoastră:
Object ancora = getParent();
while (! (ancora instanceof Frame))
ancora = ((Component)ancora).getParent();
În prima linie a codului se creează o variabilă locală, denumită ancora, care va memora în
final cadrul acestui applet. Obiectul atribuit variabilei poate fi de mai multe tipuri, aşa încât va fi
declarat de tip Object.
Următoarele două linii de cod definesc un ciclu while care apelează metoda getParent() în
lanţ, pentru fiecare obiect, până când ajunge la un obiect de tip Frame. Se observă aici că, deoarece
metoda getParent() este definită doar pentru obiectele care moştenesc clasa Component, trebuie să
convertiţi prin cast valoarea ancora la tipul Component de fiecare dată când apelaţi metoda
getParent().
După încheierea ciclului, obiectul conţinut de variabila ancora va fi o instanţă a clasei Frame
(sau a uneia dintre subclasele acesteia). Puteţi crea un obiect Dialog ataşat acestui cadru convertind
prin cast variabila ancora, pentru a vă asigura că obţineţi un obiect Frame:
TextDialog dl = new TextDialog((Frame)ancora, "Enter Text",true);

Casete de dialog pentru sistemul de fişiere

Clasa FileDialog permite crearea unei casete de dialog de tip File Open/Save (pentru
deschiderea sau salvarea fişierelor), care vă permite să accesaţi sistemul local de fişiere. Clasa
FileDialog este independentă de sistem, însă în funcţie de platformă este folosită caseta de dialog
Open File (Deschidere fişier) sau Save File (Salvare fişier).
Folosirea de instanţe ale clasei FileDialog în applet-uri depinde de browser. Din cauza
restricţiilor de securitate existente în applet-uri, majoritatea browserelor produc o excepţie de
securitate atunci când încercaţi acest lucru. Obiectele FileDialog sunt mai folositoare în aplicaţiile
independente.
Pentru a crea o casetă de dialog pentru fişiere, folosiţi unul din următorii constructori:
 FileDialog(Frame, String) creează o casetă de dialog ataşată unui cadru dat şi cu un titlu
dat, pentru încărcarea unui fişier.
 FileDialog(Frame, String, int) creează tot o casetă de dialog, însă argumentul întreg este
folosit pentru a stabili dacă este vorba despre o casetă de dialog pentru încărcarea sau pentru
salvarea unui fişier. (Singura diferenţă este eticheta butoanelor; de fapt, această casetă de
dialog nu deschide sau nu salvează nimic.) Opţiunile pentru acest argument sunt
FileDialog.LOAD sau FileDialog.SAVE.
După crearea unei instanţe a clasei FileDialog se foloseşte metoda show() pentru a o afişa:
FileDialog fd = new FileDialog(this, "FileDialog=”) ;
fd.show() ;
Atunci când utilizatorul alege un fişier şi închide caseta de dialog, el poate accesa numele fişierului
ales folosind metodele getDirectory() şi getFile(). Ambele metode returnează un şir care conţine
valorile alese de utilizator. După aceasta, puteţi deschide fişierul folosind metodele de lucru cu
fişiere şi fluxuri (streams) de date, apoi puteţi citi sau scrie din/în acest fişier.

Evenimente de fereastră

Aţi ajuns acum la ultimul tip de evenimente pe care le puteţi trata în AWT: evenimentele
pentru ferestre şi casete de dialog. (în ceea ce priveşte evenimentele, caseta de dialog este tot un tip
de fereastră.) Evenimentele de fereastră apar atunci când starea unei ferestre se modifică: de
exemplu, când este mutată, redimensionată, minimizată, restabilită, mutată în prim-plan sau închisă.
într-o aplicaţie îngrijit programată, aceste evenimente trebuie tratate - de exemplu, pentru a opri
firele aflate în execuţie atunci când o fereastră este minimizată sau pentru a „face curăţenie" la
închiderea ferestrei.
Puteţi folosi metoda handleEvent() pentru a testa evenimentele prezentate în tabelul
următor folosind instrucţiunea switch pentru variabila de instanţă id (identificator).
Evenimente de fereastră.
Numele evenimentului Când apare
WINDOW_DESTROY Generat atunci când o fereastră este închisă folosind butonul Close sau opţiunea
de meniu Close
WINDOW_EXPOSE Generat atunci când fereastra este adusă în prim-plan din spatele altor ferestre

WINDOW_ICONIFY Generat atunci când fereastra este minimizată (redusă la dimensiunea unei
pictograme)
WINDOW_DEICONIFY Generat atunci când fereastra este restabilită (când se revine de la starea de
pictogramă)
WINDOW_MOVED Generat atunci când fereastra este mutată

Meniuri

O bară de meniuri (menu bar) este o colecţie de meniuri. Un meniu, în schimb, conţine o
colecţie de opţiuni, care pot avea denumiri şi, opţional, prescurtări (shortcuts). Biblioteca AWT
oferă clase pentru toate aceste elemente de meniu, cum ar fi MenuBar, Menu şi MenuItem.
Bare de meniuri şi meniuri

O bară de meniuri (menu bar) reprezintă un set de meniuri care apare în partea de sus a unei
ferestre. Deoarece ele sunt caracteristice ferestrelor, nu puteţi crea bare de meniuri în ferestre applet
(dar, dacă applet-ul afişează o fereastră independentă, aceasta poate conţine o bară de meniuri).
Pentru a crea o bară de meniuri pentru o anumită fereastră veţi crea o instanţă a clasei
MenuBar:
MenuBar mbar = new Menubar();
Acum veţi folosi metoda setMenuBar() (definită în clasa Frame) pentru a asocia această
bară de meniuri cu fereastra:
fereastra.setMenuBar(mbar);
Puteţi adăuga meniuri individuale (File, Edit şi aşa mai departe) în bara de meniuri prin
crearea lor, urmată de adăugarea în bara de meniuri prin metoda add(). Argumentul pentru
constructorul Menu este numele meniului, aşa cum va apărea el în bara de meniuri.
Menu meniulMeu = new Menu("File") ;
mbar.add(meniulMeu) ;
Unele sisteme oferă un meniu Help special, care este afişat în partea din dreapta a barei de
meniuri, nu în partea stângă. Puteţi indica faptul că acest meniu este un meniu Help (de ajutor) prin
folosirea metodei setHelpMenu(). Meniul respectiv trebuie adăugat în bara de meniuri înainte de a
fi declarat meniu de ajutor.
Menu meniuHelp = new Menu("Help") ;
mbar.add(meniuHelp) ;
mbar.setHelpMenu(meniuHelp) ;
Dacă, pentru un motiv sau altul, doriţi ca un utilizator să nu aibă acces la un meniu, acesta
poate fi dezactivat folosind metoda disable() (şi metoda enable() pentru a-l reactiva):
meniulMeu.disable();

Elemente de meniu

În meniurile individuale puteţi adăuga patru tipuri de elemente (opţiuni):


 Instanţe ale clasei MenuItem, pentru elemente de meniu obişnuite
 Instanţe ale clasei CheckBoxMenuItem, pentru elemente de meniu care au stările
activat/dezactivat
 Alte meniuri, care conţin propriile elemente de meniu
 Separatori, pentru liniile care separă grupuri de elemente de meniu

Crearea elementelor de meniu

Elementele (opţiunile) de meniu obişnuite sunt create şi adăugate într-un meniu folosind
clasa MenuItem. Mai întâi se creează o nouă instanţă a clasei MenuItem, după care se adaugă o
componentă Menu folosind metoda add():
menu meniulMeu = new Menu("Utilitare");
meniulMeu.add(new MenuItem("Info")) ;
meniulMeu.add(new MenuItem("Culori")) ;
Submeniurile pot fi adăugate prin simpla creare a unei noi instanţe a clasei Menu şi
adăugarea în primul meniu. După aceasta, puteţi adăuga elemente în acest meniu:
Menu submeniu = new Menu("Dimensiuni") ;
meniulMeu.add(submeniu) ;
submeniu.add(new Menultem("Mic")) ;
submeniu.add(new Menultem("Mediu")) ;
submeniu.add(new Menultemf"Mare"));
Clasa CheckBoxMenuItem creează un element de meniu care posedă o casetă de validare,
permiţând ca aceasta să fie activată sau dezactivată. (Prin selectarea elementului, acesta devine
activat - în dreptul său apare un semn de validare; o nouă selectare a elementului duce la dispariţia
acestui semn şi, implicit, la dezactivarea sa). Puteţi crea şi adăuga un element de meniu de acest tip
în acelaşi fel ca elementele de meniu obişnuite:
CheckBoxMenuItem coord = new CheckBoxMenuItem("Afisare coordonate") ;
meniulMeu.add(coord) ;
Pentru a adăuga un separator într-un meniu (o linie care separă grupurile de opţiuni dintr-un
meniu), creaţi şi adăugaţi un element de meniu care să conţină ca nume o liniuţă (-). Acest element
special de meniu va fi reprezentat ca o linie de separare. Următoarele două linii de cod Java creează
un astfel de separator şi îl adaugă în meniul meniulMeu:
MenuItem sep = new Menultem("-");
meniulMeu.add(sep) ;
Orice element de meniu poate fi dezactivat folosind metoda disable(), după care poate fi
reactivat folosind metoda enable().
Elementele de meniu dezactivate nu pot fi selectate.
Menultem element = new MenuItem("Umplere") ;
meniulMeu.add(element) ;
element.disable() ;

Evenimente de meniu

Acţiunea de selectare a unui meniu cu ajutorul mouse-ului sau a comenzii rapide asociate
generează un eveniment. Puteţi trata acest eveniment folosind metoda action(), aşa cum aţi procedat
şi în aplicatiile anterioare.
În afară de evenimente de acţiune, elementele de tip checkBoxMenuItem generează
evenimente de selectare şi deselectare a listelor, care pot fi tratate cu ajutorul metodei
handleEvent().
Atunci când procesaţi evenimentele generate de elementele de meniu simple sau cele cu
casete de validare, ţineţi cont de faptul că deoarece CheckBoxMenuItem este o subclasă a
MenuItem, nu trebuie să trataţi acel element de meniu drept un caz special. Veţi trata acţiunea sa în
acelaşi mod ca pe alte acţiuni.

Crearea unor aplicaţii AWT independente


Nu există diferenţe prea mari între un applet Java şi o aplicaţie grafică Java. Tot ce aţi
învăţat până acum despre AWT, cum ar fi metodele grafice, tehnicile de animaţie, evenimente,
componente ale interfeţei, ferestre şi casete de dialog, poate fi folosit în aplicaţiile Java în acelaşi fel
în care a fost folosit în applet-uri.
Pentru crearea unei aplicaţii Java clasa aplicaţiei principale trebuie să moştenească clasa
Frame. Dacă foloseşte fire de execuţie (pentru animaţie sau alte procesări), trebuie să
implementeze, de asemenea, clasa Runnable:
class AplicatieAWT extends Frame implements Runnable {
//...
}
Pentru aplicaţia dumneavoastră veţi crea în metoda main() o nouă instanţă a clasei; deoarece
clasa moşteneşte clasa Frame, veţi obţine o nouă fereastră AWT, pe care apoi o puteţi
redimensiona şi afişa ca pe orice fereastră AWT.
Caracteristicile AWT normale pentru o fereastră, care se declarau de obicei în cadrul
metodei init() a unui applet, se realizează aici în cadrul metodei constructor a clasei: se stabileşte
titlul, se declară un administrator de dispunere, se creează şi adaugă componente cum ar fi bara de
meniuri sau alte elemente de interfaţă, se lansează fire de execuţie şi aşa mai departe.
Un exemplu de aplicaţie simplă:

import java.awt.* ;
class AplicatieAWT extends Frame {
AplicatieAWT(String titlu) {
super(titlu) ;
setLayout(new FlowLayout()) ;
add(new Button("OK") ;
addtnew Button("Reset");
addtnew Button("Cancel”) ;
}
public static void main(String args[ ) {
AplicatieAWT apl = new AplicatieAWT("Prima aplicatie") ;
apl.resize(300, 300);
apl.show() ;
}
}
Pentru controlul şi administrarea unei aplicaţii puteţi folosi aproape oricare dintre metodele
despre care aţi învăţat. Singurele metode care nu pot fi folosite sunt cele specifice applet-urilor
(adică cele definite în java.applet.Applet, cum ar fi cele pentru apelarea informaţiilor de la diferite
adrese URL sau pentru redarea clipurilor audio).
Este bine de cunoscut încă o diferenţă între aplicaţii şi applet-uri: atunci când trataţi un
eveniment de închidere a unei ferestre, în afară de ascunderea sau distrugerea ferestrei trebuie să
mai apelaţi şi metoda System.exit(0), care indică sistemului că aplicaţia dumneavoastră s-a
terminat.
public void închidereFereastra(WindowEvent e) {
fr.hide() ;
fr.destroy() ;
System.exit(0) ;
}

Exceptii Java
Până în acest moment, este mai mult ca sigur că aţi întâlnit cel puţin o situaţie de excepţie
Java - probabil atunci când aţi introdus greşit numele unei metode sau aţi făcut o greşeală în cod
care a dus la apariţia unei probleme.
Se poate, de asemenea, ca programul să se termine anormal, după ce a afişat pe ecran ceva
erori. Aceste erori sunt excepţii. Atunci când programul se termină brusc, este din cauză că a fost
semnalată o excepţie (thrown - „aruncată"). Excepţiile fi semnalate de sistem sau, explicit, de
programul pe care l-aţi scris.
Am folosit termenul "semnalate" deoarece excepţiile pot fi şi interceptate (caught).
Interceptarea unei excepţii presupune tratarea situaţiilor speciale pentru ca programul
dumneavoastră să nu se mai blocheze. Faptul că o excepţie a fost semnalată înseamnă, în Java, că "a
apărut o eroare".
Excepţiile Java sunt, de fapt, obiecte, instanţe ale unor clase care moştenesc clasa
Throwable. O instanţă a clasei Throwable este creată atunci când se semnalează o excepţie. Figura
următoare prezintă o porţiune ierarhiei de clase pentru excepţii.

Throwable

Error Exception

IOException
RuntimeException

FileNotFound
ClassNotFoundE Exception
xception
EOFException
AWTException

MalFormedURL
Exception

SocketException

Clasa Throwable are două subclase: Error şi Exception. Instanţele clasei Error reprezintă
erori interne ale mediului de lucru Java (maşina virtuală). Aceste erori sunt rare şi, de obicei, fatale;
nu puteţi face mare lucru cu ele (nici să le interceptaţi şi nici să le semnalaţi), există pentru ca Java
să le poată folosi dacă are nevoie de ele.
Subclasele Exception se împart în două grupuri:
 Excepţii de execuţie (runtime), care sunt subclase ale clasei RuntimeException, cum ar fi
ArrayIndexOutofBounds, SecurityException sau NullPointerException
 Alte excepţii, cum ar fi EOFException sau MalformedURLException
Majoritatea claselor de excepţie fac parte din pachetul java.lang (cum ar fi Throwable,
Exception sau RuntimeException). Celelalte pachete definesc şi ele excepţii, care pot fi folosite în
toată biblioteca de clase. De exemplu, pachetul java.io defineşte o clasă de excepţie generică,
denumită IOException, care nu este folosită doar în pachetul java.io, pentru excepţiile de
intrare/ieşire (EOFException, FileNotFoundException), ci şi în clasele pachetului java.net, pentru
excepţii de reţea cum ar fi MalformedURLException.

Gestionarea excepţiilor

În majoritatea cazurilor, compilatorul Java impune gestionarea excepţiilor atunci când


încercaţi să folosiţi metode ce presupun apariţia unor excepţii; dacă nu trataţi aceste excepţii, codul
nu va fi compilat. În această secţiune veţi învăţa despre verificarea consistenţei şi despre folosirea
cuvintelor cheie try, catch şi finally pentru tratarea excepţiilor ce pot apărea.

Verificarea consistenţei excepţiilor

Cu cât lucraţi mai mult cu biblioteci Java, cu atât mai mult creşte posibilitatea de a întâlni o
eroare (o excepţie!) de compilare, asemănătoare acesteia:
Program.java:32: Exception java.lang.InterruptedException must be
caught or it must be declared in the throws clause of this method.
(Program.java:32: Excepţia java.lang.InterruptedException trebuie interceptată sau trebuie declarată
în clauza throws a acestei metode.)
În Java, o metodă poate indica tipurile de erori pe care le poate semnala. De exemplu,
metodele care citesc din fişiere pot semnala excepţii IOException, deci aceste metode sunt
declarate cu un modificator special care indică potenţialele erori. Atunci când folosiţi aceste metode
în programele dumneavoastră Java, trebuie să vă protejaţi codul împotriva acestor excepţii. Această
regulă este verificată chiar de compilator, în acelaşi fel în care verifică şi dacă aţi apelat metodele cu
numărul corespunzător de argumente sau dacă aţi atribuit variabilelor tipurile de date declarate.
De ce se face această verificare? Deoarece astfel programele dumneavoastră sunt mai puţin
expuse erorilor fatale şi terminării anormale, pentru că ştiţi dinainte ce tipuri de excepţii pot fi
semnalate de metodele folosite în program. Nu trebuie să mai citiţi cu atenţie documentaţia sau
codul unui obiect pentru a vă asigura că aţi tratat toate potenţialele probleme - Java face aceste
verificări în locul dumneavoastră. Pe de altă parte, dacă definiţi metodele astfel încât să indice
excepţiile pe care le pot semnala, Java poate avertiza utilizatorii acestor obiecte că trebuie să trateze
erorile respective.

Protejarea codului şi interceptarea erorilor

Să presupunem că aţi scris un cod şi că la un test de compilare aţi obţinut un mesaj de


excepţie. În funcţie de mesaj, fie interceptaţi eroarea, fie declaraţi că metoda o poate semnala. Să
luăm primul caz: interceptarea potenţialelor excepţii.
Pentru a intercepta o excepţie trebuie realizate două lucruri:
 Protejaţi codul care conţine metoda ce poate semnala excepţia în cadrul unui bloc try.
 Testaţi şi trataţi excepţia în cadrul unui bloc catch.
Operaţiunile try (încearcă) şi catch (interceptează) înseamnă, de fapt, „încearcă această
porţiune de cod, care poate cauza o excepţie. Dacă se execută cu succes, continuă programul. dacă
nu, interceptează excepţia şi trateaz-o."
Un astfel de caz este atunci când creaţi animaţie pe care o opriţi o dată pe secundă:
try {
Thread.sleep(1000);
} catch (InterruptedException e) { }
Chiar dacă aici s-au folosit instrucţiunile try şi catch, acesta nu este un exemplu prea bun.
Iată ce se întâmplă în aceste instrucţiuni: metoda de clasă Thread.sleep() poate să semnaleze o
excepţie de tip InterruptedException, ceea ce înseamnă că firul de execuţie a fost oprit dintr-un
motiv oarecare.
Pentru a trata această excepţie, apelul metodei sleep() este încadrat într-un bloc try, după
care se defineşte un bloc catch asociat. Acest bloc catch primeşte toate obiectele
InterruptedException care sunt semnalate din blocul try.
Motivul pentru care acest cod nu constituie un bun exemplu de tratare a excepţiilor este că
nu există nimic în interiorul blocului catch - cu alte cuvinte, se interceptează excepţia atunci când
apare, însă ca răspuns la aceasta nu se face nimic. Cu excepţia cazurilor simple (cum e acesta, unde
excepţia într-adevăr nu contează), trebuie să scrieţi în cadrul blocului catch un cod care să realizeze
o anumită acţiune după apariţia excepţiei.
Partea din interiorul instrucţiunii catch este similară listei de argumente a unei metode. Ea
conţine clasa a cărei excepţie a fost interceptată şi un nume de variabilă (de obicei se foloseşte e).
Astfel, în cadrul blocului puteţi să vă referiţi la obiectul excepţie interceptat.
O folosire uzuală a acestui obiect este apelarea metodei getMessage(). Această metodă este
prezentă în toate excepţiile şi afişează un mesaj detaliat referitor la ceea ce s-a întâmplat.
Următorul exemplu reprezintă o versiune revizuită a instrucţiunii try.. . catch,din exemplul
anterior:
try {
Thread.sleep(1000) ;
} catch (InterruptedException e) {
System.out.println("Eroare: " + e.getMessage());
}

Clauza finally

Să presupunem că în codul dumneavoastră există o anumită acţiune care trebuie neapărat


executată, indiferent ce se întâmplă, indiferent dacă excepţia este semnalată sau nu. Acest lucru se
face, de obicei, pentru a elibera anumite resurse după folosire, pentru a închide un fişier după
deschidere sau ceva de acest gen. Chiar dacă puteţi introduce aceste acţiuni atât în cadrul unui bloc
catch, cât şi în afara sa, aceasta înseamnă o duplicare a codului în două locuri diferite. În loc să
procedaţi astfel, introduceţi o copie a codului într-o porţiune specială a blocului try. . .catch,
denumită finally.
Următorul exemplu prezintă modul cum este structurat un bloc try. . .catch . . . finally:
try {
citesteFisierText();
} catch (IOException e) {
// tratati erorile de intrare/iesire
} finally {
inchideFisierText() ;
}
Instrucţiunea finally este folositoare, de fapt, în afara excepţiilor; puteţi, de asemenea, să o
folosiţi pentru executarea unui cod de reiniţializare după o instrucţiune return, break sau continue
din cadrul unui ciclu. În ultimul caz puteţi folosi o instrucţiune try doar cu blocul finally, fără
blocul catch.

Declararea metodelor care pot semnala exceptii

În exemplele anterioare aţi învăţat cum se tratează metodele care pot semnala excepţii (prin
protejarea codului şi interceptarea eventualelor excepţii). Compilatorul Java verifică dacă v-aţi
ocupat într-un fel sau altul de excepţiile care pot apărea - dar cum ştie el asupra căror excepţii să vă
atragă atenţia?
Răspunsul este că metoda originală indică în semnătura sa excepţiile pe care le poate
semnala. Puteţi folosi acest mecanism în propriile metode, de fapt, este bine să procedaţi astfel
pentru a vă asigura că utilizatorii vor fi avertizaţi asupra excepţiilor ce pot apărea.
Pentru a indica faptul că o metodă poate semnala o excepţie, veţi folosi în definiţia sa o
clauză specială, denumită throws.
Clauza throws

Pentru a indica faptul că o porţiune a unei metode poate semnala o excepţie, este suficient să
adăugaţi cuvântul cheie throws după semnătura metodei (înainte de acolada deschisă) şi să
specificaţi numele excepţiilor pe care le poate semnala metoda dumneavoastră:
public boolean metodaMea(int x, int y) throws oExceptie {
// ...
}
Dacă metoda dumneavoastră poate semnala mai multe tipuri de excepţii, puteţi să le
specificaţi pe toate în clauza throws, separate prin virgule:
public boolean oAltaMetodaAMea(int x, int y)
throws oExceptie, oADouaExceptie, oATreiaExceptie {
// ...
}
La fel ca în cazul catch, puteţi folosi o superclasă a unui grup de excepţii pentru a indica
faptul că metoda dumneavoastră poate semnala oricare dintre subclasele acelei excepţii:
public void oAltaMetoda() throws IOException {
// .. .
}
Specificarea clauzei throws în definiţia metodei dumneavoastră nu înseamnă decât că
metoda poate semnala o excepţie dacă ceva merge prost, nu şi că va face acest lucru. Clauza throws
oferă doar o informaţie suplimentară referitoare la potenţialele excepţii şi permite compilatorului
Java să se asigure că metoda este corect folosită de utilizatori.

Manipularea datelor prin fluxuri Java


Majoritatea programelor pe care le creaţi în Java trebuie să interacţioneze cu anumite surse
de date. Există nenumărate metode de păstrare a informaţiilor pe un calculator, cum ar fi fişiere pe
hard disc sau pe CD-ROM, pagini într-un site Web sau chiar în memoria calculatorului.
Aţi putea crede că există diferite tehnici pentru manipularea datelor de pe diversele
dispozitive de stocare. Din fericire, nu este cazul. În Java, informaţiile pot fi stocate sau apelate
folosind un sistem de comunicaţie denumit flux (stream), implementat în pachetul java.io.
Fluxurile reprezintă un mecanism puternic de manipulare a datelor.

Introducere în fluxuri

Toate datele din Java sunt scrise sau citite folosind fluxuri. Fluxurile, aşa cum le arată şi
denumirea, transportă ceva dintr-un loc în altul.
Un flux (stream) reprezintă calea pe care o urmează datele într-un program. Un flux de
intrare transportă datele de la sursă la program, iar un flux de ieşire transportă datele din program
către o destinaţie.
Există două tipuri de fluxuri: fluxuri de octeţi şi fluxuri de caractere. Octeţii pot păstra
valori întregi din domeniul 0. . . 255. În acest format pot fi reprezentate o multitudine de date, cum
ar fi date numerice, programe executabile, comunicaţii Internet sau cod Java (bytecode) - adică
fişierele clasă care sunt executate pe o maşină virtuală Java. De fapt, orice tip de date poate fi
reprezentat printr-o serie de octeţi.
Fluxurile de caractere reprezintă un tip special de fluxuri de octeţi, care se folosesc numai
pentru datele de tip text (tipăribile). Ele diferă de fluxurile de octeţi prin faptul că setul de caractere
Java suportă codificarea Unicode, un standard prin care se pot reprezenta mai multe caractere decât
dacă s-ar folosi octeţi.
Toate datele de tip text, cum ar fi fişierele text, paginile Web sau alte formate de text, trebuie
să folosească fluxuri de caractere.
Folosirea unui flux
Indiferent dacă folosiţi fluxuri de octeţi sau de caractere, procedura este asemănătoare.
În cazul şirurilor de intrare, prima etapă constă în crearea unui obiect asociat cu sursa de
date. De exemplu, dacă sursa este un fişier de pe hard discul dumneavoastră, acestuia trebuie să i se
asocieze un obiect de tip FileInputStream.
0 dată obţinut obiectul asociat fluxului, puteţi citi informaţii din acest flux folosind una
dintre metodele obiectului. Clasa FileInputStream posedă o metodă read(), care returnează un
octet citit din fişier.
Atunci când aţi terminat de citit informaţia din flux, trebuie să apelaţi metoda close(), pentru
a indica faptul că aţi terminat de folosit fluxul.
În cazul fluxurilor de ieşire, veţi începe prin a crea un obiect asociat cu destinaţia datelor.
Un astfel de obiect poate fi creat pornind de la clasa BufferedReader, care constituie o metodă
eficientă de creare a fişierelor text.
Metoda write() reprezintă cea mai simplă metodă de a transmite informaţii către destinaţia
unui flux. De exemplu, metoda write() aparţinând dasei BufferedReader poate transmite caractere
individuale unui flux de ieşire.
Ca şi în cazul fluxurilor de intrare, pentru un flux de ieşire trebuie apelată metoda close ()
atunci când nu mai există date de transmis.
Filtrarea unui flux
Cea mai simplă metodă de a folosi un flux este de a îl crea şi de a-i apela metodele de
transmitere sau de recepţie a datelor, în funcţie de rolul lui (flux de intrare sau flux de ieşire).
Majoritatea claselor folosite în prezent permit obţinerea unor rezultate mai sofisticate prin
asocierea fluxului cu un filtru, înainte de a citi sau scrie date.
Un filtru este un tip de flux care schimbă modul în care se lucrează cu un flux existent.
Procedura de folosire a unui filtru pentru un flux presupune următoarele:
• Crearea unui flux asociat cu sursa de date sau cu destinaţia datelor.
• Asocierea unui filtru cu acest flux.
• Citirea şi scrierea datelor de la/în filtru, şi nu direct în flux.
Metodele pe care le apelaţi în cazul filtrelor sunt aceleaşi cu cele pe care le apelaţi în cadrul
fluxurilor: există metodele read () şi write (), asemănătoare celor ale unui flux nefiltrat.
Puteţi chiar să asociaţi un filtru unui alt filtru, creând situaţii de genul: un flux de intrare este
asociat unui fişier text, este trecut printr-un filtru de traducere româno-englez şi, în final, este trimis
la destinaţie - o persoană care doreşte să îl citească.

Fluxuri de octeţi

Toate fluxurile de octeţi sunt subclase ale InputStream sau OutputStream. Aceste clase
sunt abstracte, deci nu puteţi obţine un flux prin crearea de obiecte direct din aceste clase. În
schimb, puteţi crea fluxuri prin folosirea unor subclase ale acestora, cum ar fi:
| • FileInputStream şi FileOutputStream-Octeţi stocaţi în fişiere pe disc, pe CD-ROM sau pe
alte dispozitive de stocare.
• DataInputStream şi DataOutputStream - Un flux de octeţi filtrat, din care pot fi citite date
de tip întreg sau în virgulă mobilă (float). InputStream este superclasa tuturor fluxurilor de intrare.
Fluxuri de fişiere
Fluxurile de octeţi cu care veţi lucra de obicei sunt fluxuri de fişiere folosite pentru
transferul de date între program şi fişierele aflate pe hard discuri, pe CD-ROM sau pe alte
dispozitive de stocare ce pot fi referite printr-o cale de director şi un nume.
Puteţi transmite octeţi unui flux de ieşire şi puteţi citi octeţi dintr-un flux de intrare.
Fluxuri de intrare din fişiere
Un flux de intrare din fişier poate fi creat cu ajutorul constructorului FileInputStream
(String). Şirul transmis ca argument trebuie să fie numele fişierului. Puteţi include şi calea către
fişier, în cazurile în care acesta se află în alt director decât cel care conţine clasa. Următoarea
instrucţiune creează un flux de intrare pentru fişierul date.dat:
FileInputStream fis = new FileInputStream("date.dat") ;
După crearea fluxului de intrare din fişier, puteţi citi octeţi din acesta apelându-i metoda
read (). Această metodă returnează o valoare întreagă ce conţine următorul octet din flux. Dacă
metoda retumează -1, care nu este o valoare acceptată pentru un octet, înseamnă că s-a ajuns la
sfârşitul fluxului de fişier.
Pentru a citi mai mulţi octeţi din flux se foloseşte metoda read(byte[], int, int), care posedă
următoarele argumente:
• Un tablou de octeţi în care se vor memora datele
• Elementul din cadrul tabloului unde se va stoca primul octet de date
• Numărul de octeţi care se vor citi
Spre deosebire de alte metode read (), aceasta nu retumează date din flux, ci un întreg care
reprezintă numărul de octeţi citiţi sau -1 dacă nu s-au citit octeţi şi s-a ajuns la sfârşitul fluxului.
Următoarele instrucţiuni folosesc un ciclu while pentru a citi datele din obiectul df de tip
FileInputStream:
int octetNou = 0;
while (octetNou != -1) {
octetNou = df.read();
System.out.println(octetNou +" ”);
}
Această buclă citeşte întregul fişier referit de obiectul df, câte un octet o dată, şi afişează valoarea
fiecărui octet, urmată de un spaţiu. De asemenea, când se ajunge la sfârşitul fişierului va fi afişată
valoarea -1, lucru pe care îl puteţi evita folosind un test if.
Fluxuri de ieşire în fişiere
Un flux de ieşire în fişier poate fi creat folosind constructorul FileOutputStream (String).
Utilizarea sa este identică cu cea a constructorului FileInputStream (String), deci puteţi specifica
şi calea până la fişier, nu numai numele acestuia.
Trebuie să aveţi grijă atunci când specificaţi fişierul în care scrieţi. Dacă folosiţi numele unui fişier
deja existent, o dată cu începerea scrierii datelor, acesta va fi şters definitiv.
Puteţi crea un flux de ieşire în fişier care să adauge date (append) la sfârşitul unui fişier existent
folosind constructorul FileOutputStream(String, boolean). Şirul specifică numele fişierului, iar
argumentul boolean, dacă are valoarea true, va adăuga datele la sfârşitul fişierului, în loc să
suprascrie datele existente.
Pentru a scrie octeţi într-un fişier se foloseşte metoda write ( int) a fluxului de ieşire. După ce s-a
scris ultimul octet, fluxul trebuie închis folosind metoda close ().
Pentru a scrie mai mulţi octeţi se poate folosi metoda write(byte[], int, int), care funcţionează
similar metodei read (byte[], int, int) descrisă anterior. Argumentele acestei metode sunt tabloul
care conţine octeţii ce vor fi scrişi, poziţia de început din tablou şi numărul de octeţi ce trebuie
scrişi.
Filtrarea fluxurilor

Fluxurile filtrate sunt fluxuri care modifică informaţia trimisă printr-un flux existent.
Acestea sunt create folosind subclase ale FilterInputStream sau FilterOutputStream.
Aceste filtre nu realizează singure nici un fel de operaţie de filtrare. De fapt, ele posedă
subclase, cum ar fi BufferInputStream sau DataOutputStream, care sunt folosite pentru anumite
tipuri de filtrări.

Filtre de octeti

Informaţia este furnizată mai rapid dacă poate fi transmisă în blocuri de date mai mari, chiar
dacă aceste blocuri sunt recepţionate mai repede decât pot fi procesate.
Un tampon (buffer) reprezintă o zonă în care se pot păstra date înainte de a fi nevoie să fie
citite sau scrise de un program. Prin folosirea unui tampon puteţi avea acces la date fără să accesaţi
din nou sursa originală de date.
Fluxuri cu tampon
Un flux de intrare cu tampon umple un tampon cu date care nu au fost încă procesate; când
programul are nevoie de aceste date, le caută în zona tampon înainte de a apela fluxul sursă original.
Această tehnică este mai eficientă. Această descongestionare a fluxului nu face altceva decât să
uşureze eforturile de folosire a acestuia. Fluxurile de octeţi folosesc clasele BufferedInputStream
şi BufferedOutputStream.
Fluxurile de intrare cu tampon sunt create folosind unul din constructorii:
• BufferedInputStream(InputStream) Creează un flux de intrare cu tampon pentru obiectul
InputStream specificat.
• BufferedInputStream(InputStream, int) Creează fluxul de intrare cu tampon InputStream
specificat, având o dimensiune a zonei tampon egală cu valoarea argumentului întreg.
Cea mai uşoară modalitate de a citi date dintr-un flux de intrare cu tampon este de a apela metoda
read () a acestuia, fără argumente; aceasta retumează o valoare întreagă între 0 şi 255, care
reprezintă următorul octet din flux. Dacă s-a ajuns la sfârşitul fluxului şi nu s-a găsit nici un octet,
se retumează valoarea -1.
Puteţi, de asemenea, folosi metoda read(byte [] , int, int), care este disponibilă şi pentru alte fluxuri
de intrare, caz în care datele sunt încărcate într-un tablou de octeţi.
Un flux de ieşire cu tampon este creat prin folosirea următorilor constructori:
• BufferedOutputStream(OutputStream) Creează un flux de ieşire cu tampon pentru obiectul
OutputStream specificat.
• BufferedOutputStream(OutputStream, int) Creează fluxul de ieşire cu tampon OutputStream
specificat, alocând o zonă tampon de dimensiunea specificată prin argumentul int.
Pentru a scrie un singur octet în fluxul de ieşire poate fi folosită metoda write(int) a acestuia, iar
pentru a scrie mai mulţi octeţi dintr-o dată se poate folosi metoda write (byte [ ], int, int).
Argumentele acestei metode sunt tabloul de octeţi, poziţia iniţială a acestuia şi numărul de octeţi
care trebuie transmis.
Atunci când datele sunt direcţionate într-un flux cu tampon, conţinutul acestuia nu va fi transmis
către destinaţie decât după ce zona tampon s-a umplut sau dacă se apelează explicit metoda flush()
a fluxului.
Fluxuri de date
Dacă trebuie să lucraţi cu date care nu sunt reprezentate drept octeţi sau caractere, puteţi
folosi fluxuri de date de intrare şi de ieşire. Aceste fluxuri filtrează un flux de octeţi existent astfel
încât următoarele tipuri de date să poată fi citite direct din flux: boolean, byte, double, float, int,
long şi short.
Un flux de date de intrare este creat folosind constructorul DataInputStream (InputStream).
Argumentul trebuie să fie un flux de intrare existent, de exemplu, un flux de intrare cu tampon sau
un flux de intrare din fişier. Reciproc, un flux de date de ieşire necesită utilizarea constructorului
DataOutputStream (OutputStream), care foloseşte ca argument fluxul de ieşire asociat.
Următoarea listă prezintă metodele de citire şi de scriere ce pot fi folosite pentru fluxurile de date de
intrare, respectiv de ieşire:
• readBoolean(), writeBoolean(boolean)
• readByte(), writeByte (int)
• readDouble(), writeDouble(double) :
• readFloat(), writeFloat(float)
• readInt(), writeInt(int)
• readLong(), writeLong(long)
• readShort(), writeShort(int)
Fiecare dintre metodele de intrare returnează tipul de dată primitivă indicat de numele metodei. De
exemplu, metoda readFloat () retumează o valoare float.
Există şi metodele readUnsignedByte () şi readUnsignedShort (), care pot citi valori de tip octet
sau întregi scurţi fără semn. Aceste tipuri de date nu sunt suportate în Java, deci vor fi retumate ca
valori întregi.
Octeţii fără semn iau valori de la 0 la 255. Aceasta diferă de tipul de variabilă byte din Java, care ia
valori între -128 şi 127. în acelaşi fel, o variabilă întreagă scurtă fără semn ia valori între 0 şi
65535, în loc de domeniul -32768 şi 32767, suportat de tipul short în Java.
Nu toate metodele de citire dintr-un flux de date de intrare retumează o valoare ce poate indica
faptul că s-a ajuns la sfârşitul fluxului. Vă mai puteţi aştepta la apariţia excepţiei EOFException
care este semnalată la atingerea sfârşitului unui flux. Ciclul în care se citesc date poate fi încadrat
într-un bloc try, iar instrucţiunea catch asociată trebuie să trateze doar excepţiile EOFException.
In cadrul blocului catch puteţi să apelaţi şi metoda close () şi să efectuaţi alte acţiuni de
reiniţializare.

Fluxuri de caractere

Aceste fluxuri se folosesc pentru lucrul cu orice text reprezentat în format ASCII sau
Unicode .
Clasele folosite pentru a citi şi scrie aceste fluxuri sunt subclase ale daselor Reader şi
Writer. Este indicat să folosiţi aceste clase pentru lucrul cu text, şi nu fluxuri de octeţi.
Tehnicile pentru lucrul cu fluxuri de caractere s-au îmbunătăţit considerabil în versiunile
ulterioare Java 1.02, o dată cu introducerea claselor Reader şi Writer şi a subclaselor acestora; ele
oferă suport pentru setul de caractere Unicode şi permit o manevrare mai uşoară a textelor. Un
applet java compatibil cu versiunea 1.02 poate citi caracterele folosind clasele pentru fluxuri de
octeţi descrise anterior.
Citirea fişierelor text
Principala clasă folosită pentru citirea de fluxuri de caractere dintr-un fişier este FileReader.
Această clasă moşteneşte clasa InputStreamReader, care citeşte un flux de octeţi şi îi converteşte
în valorile întregi corespunzătoare caracterelor Unicode.
Un flux de intrare de caractere este asociat unui fişier folosind constructorul FileReader (String).
Şirul reprezintă numele fişierului şi poate conţine şi calea până la acesta.
Următoarea instrucţiune creează un obiect FileReader denumit web şi îl asociază cu fişierul text
denumit index. html:
FileReader web = new FileReader("index.html”);
După ce aţi obţinut un obiect de acest tip, puteţi să apelaţi următoarele metode de citire a
caracterelor din fişier:
• read () returnează următorul caracter din flux, ca valoare întreagă
• read (char [ ], int, int) citeşte caractere într-un tablou şi primeşte ca argumente tabloul de
caractere, poziţia de începere şi numărul de caractere de citit. A doua metodă funcţionează
asemănător echivalentului său din clasele de fluxuri de intrare de octeţi. În loc să returneze
caracterul următor din flux, aceasta returnează fie numărul de caractere citite, fie -1 dacă s-a ajuns
la sfârşitul fluxului şi nu s-a citit nimic.
Următoarea metodă încarcă un fişier text folosind obiectul FileReader şi afişează caracterele
conţinute de acesta:
FileReader text = new FileReader("readme.txt");
int octetCitit;
do {
octetCitit = text.read();
if (octetCitit != -1)
System.out.print( (char)octetCitit) ;
} while (octetCitit != -1) ;
System.out.println(" ");
text.close() ;
Deoarece metoda read () a unui flux de caractere returnează o valoare întreagă, trebuie să convertiţi
prin cast această valoare înainte de a o afişa, de a o salva într-un tablou sau de a o folosi într-un şir.
Fiecare caracter posedă un cod numeric care reprezintă poziţia sa în setul de caractere Unicode.
Valoarea întreagă citită din flux reprezintă chiar acest cod numeric. Dacă doriţi să citiţi din fişier o
întreagă linie de text, şi nu caracter cu caracter, puteţi folosi o combinaţie a daselor FileReader şi
BufferedReader.
Clasa BufferedReader citeşte un caracter din fluxul de intrare şi îl memorează într-o zonă tampon,
pentru mai multă eficienţă. Pentru a crea o versiune care foloseşte tampon, trebuie să existe un
obiect de tip Reader. Pentru crearea obiectului BufferedReader se pot folosi următorii
constructori:
• BufferedReader(Reader) Creează un flux de caractere cu zonă tampon, asociat obiectului
Reader specificat (de exemplu FileReader).
• BufferedReader (Reader, int) Creează un flux de caractere asodat obiectului Reader, cu o zonă
tampon de dimensiunea specificată de argumentul întreg.
Dintr-un flux de caractere cu tampon se poate citi folosind metodele read () şi read(char[ ] , int,
int), asemănătoare celor descrise pentru FileReader. Puteţi citi o întreagă linie de text folosind
metoda readLine ().
Metoda readLine () returnează un obiect String care conţine următoarea linie de text din flux, fără a
include şi caracterul (sau caracterele) care reprezintă sfârşitul de linie. Dacă se ajunge la sfârşitul
fluxului, valoarea şirului returnat va fi null.
Sfârşitul de linie este indicat astfel:
• Un caracter de linie nouă (newline - '\n')
• Un caracter de retur de car (carriage retum – ’\r’)
• Un retur de car urmat de o linie nouă
Scrierea în fişiere text
Clasa FileWriter este folosită pentru scrierea unui flux de caractere într-un fişier. Aceasta
este o subclasă a OutputStreamWriter, care are rolul de a converti codurile caracterelor Unicode
în octeţi.
Există doi constructori FileWriter: FileWriter (String) şi FileWriter (String, boolean).
Şirul din primul argument reprezintă numele fişierului către care va fi direcţionat fluxul de caractere
şi poate conţine şi calea. Argumentul opţional de tip boolean trebuie să ia valoarea true dacă se
doreşte ca datele să fie adăugate la sfârşitul unui fişier existent. Ca şi în cazul altor clase de scriere
în fluxuri, trebuie să aveţi grijă să nu suprascrieţi accidental un fişier existent.
Clasa FileWriter conţine trei metode ce pot fi folosite pentru a scrie date într-un flux:
• write(int) Scrie un caracter.
• write(char [], int, int) Scrie caracterele din tabloul specificat, începând de la poziţia dată şi
având numărul de caractere dat.
• write(String, int, int) Scrie caractere din şirul specificat, începând de la poziţia dată şi având
numărul de caractere dat.
Următorul exemplu scrie un flux de caractere într-un fişier folosind clasa FileWriter şi metoda
write (int):
FileWriter litere = new FileWriter("alfabet.txt");
for (int i = 65; i < 91; i++) litere.write((char)i) ;
litere.close() ;
Metoda close () este folosită pentru închiderea fluxului, după ce toate caracterele au fost trimise în
fişierul destinaţie. lată conţinutul fişierului alfabet.txt produs de acest cod:
ABCDEFGHIJKLMNOPQRSTUVXYZ
Clasa BufferedWriter poate fi folosită pentru scrierea într-un flux de caractere cu zonă tampon.
Obiectele acestei clase sunt create folosind constructorul BufferedWriter (Writer) sau
BufferedWriter (Writer, int). Argumentul Writer poate fi oricare dintre clasele de fluxuri de
caractere de ieşire, cum ar fi FileWriter. Al doilea argument, opţional, este o valoare întreagă ce
indică dimensiunea zonei tampon care va fi folosită.
BufferedWriter posedă aceleaşi trei metode de ieşire ca şi FileWriter: write(int),
write(char[], int, int) şi write(String, int, int).
0 altă metodă folositoare este newLine (), care trimite caracterul (sau caracterele) ce specifică
sfârşitul liniei pe platforma folosită pentru rularea programului.
Diferitele caractere de sfârşit de linie pot crea neplăceri la transferul unui fişier de pe un sistem de
operare pe altul, cum ar fi cazul când un utilizator Windows 95 copiază un fişier pe un server Web
care foloseşte sistemul de operare Linux. Folosind metoda newLine() în loc de un literal (cum ar fi
'\n'), puteţi utiliza programul dumneavoastră pe diferite platforme.
Metoda close () este apelată pentru a închide fluxul de caractere de ieşire şi pentru a asigura că toate
datele memorate în zona tampon au fost trimise către destinaţia fluxului.

Filtre de fişiere şi de nume de fişiere

În toate exemplele de până acum, pentru referirea la numele fişierului implicat într-o
operaţie cu fluxuri s-a folosit un şir. De multe ori, acest lucru este suficient, însă dacă doriţi să
copiaţi, să redenumiţi sau să realizaţi alte activităţi cu fişiere, puteţi folosi şi obiecte de tip File.
Clasa File, care face şi ea parte din pachetul java.io, reprezintă o referinţă către un fişier sau
un director. Pot fi folosiţi următorii constructori File:
• File ( String) Creează un obiect File pentru directorul specificat - nu este indicat nici un nume
de fişier, deci acesta se referă doar la un director.
• File(String, String) Creează un obiect File pentru directorul specificat şi pentru fişierul cu
numele specificat.
• File(File, String) Creează un obiect File a cărui cale este specificată de obiectul File şi al cărui
nume este dat de şirul specificat.
Într-un obiect de tip File puteţi apela mai multe metode folositoare. Metoda exists () returnează o
valoare boolean care arată dacă fişierul există sub numele şi în directorul specificate la crearea
obiectului File. Dacă fişierul există, puteţi folosi metoda length(), care retumează o valoare de tip
întreg long ce reprezintă dimensiunea fişierului în octeţi.
Metoda renameTo (File) redenumeşte fişierul sub numele specificat de argumentul File. Se
retumează o valoare boolean, care indică dacă operaţia s-a finalizat cu succes sau nu.
Metoda delete () sau deleteOnExit () se apelează pentru ştergerea unui fişier sau a unui folder.
Metoda delete () încearcă să facă imediat ştergerea (şi returnează o valoare boolean care indică
succesul operaţiei). Metoda deleteOnExit () aşteaptă şi încearcă să şteargă fişierul după ce restul
programului şi-a terminat execuţia. Această metodă nu retumează nici o valoare iar programul
trebuie să se termine la un moment dat pentru ca metoda să funcţioneze.
Metoda mkdir () se foloseşte pentru a crea un director specificat de obiectul File pentru care s-a
apelat. Aceasta retumează o valoare boolean care indică succesul sau eşecul operaţiei. Nu există o
metodă echivalentă pentru ştergerea directoarelor, deoarece metoda delete () poate fi folosită la fel
de bine şi pentru directoare şi pentru fişiere.
Ca în cazul tuturor operaţiilor care implică lucrul cu fişiere, aceste metode trebuie folosite cu grijă
pentru a evita ştergerea unor fişiere sau directoare sau suprascrierea unor fişiere. Nu există nici o
metodă pentru recuperarea fişierelor sau a directoarelor şterse.
Fiecare dintre aceste metode va semnala o excepţie SecurityException dacă programul nu are
permisiunile necesare pentru executarea operaţiilor respective, deci trebuie folosite blocuri try. . .
catch sau clauze throws pentru a trata aceste excepţii.

S-ar putea să vă placă și