Documente Academic
Documente Profesional
Documente Cultură
-tipuri de fluxuri de intrare/iesire Java: fluxuri de octeti, fluxuri de caractere; System.in, System.out, System.err; fluxuri-filtre; - fluxuri de octeti si clase predefinite Java utilizate: fluxuri nefiltrate de intrare care folosesc ca sursa un fiser; fluxuri nefiltrate de iesire care folosesc ca destinatie un fisier; - filtrarea fluxurilor de octeti si clase predefinite Java utilizate: zona tampon (buffer); fluxuri de intrare cu o zona tampon; fluxuri de iesire cu o zona tampon; fluxuri filtrate cu date de tipuri primitive; fluxuri filtrate cu date formatate; - fluxuri de caractere si clase predefinite Java utilizate: fluxuri nefiltrate de intrare care folosesc ca sursa un fisier; fluxuri filtrate de intrare cu o zona tampon; fluxuri filtrate de intrare cu o zona tampon care tin evidenta numerelor de linie.
3/2/2014
- fluxuri de octeti;
- fluxuri de caractere. Fluxurile de octeti pot pastra valori intregi din domeniul 0 - 255. In acest format pot fi reprezentate o multitudine de date, cum ar fi: date numerice, programe executabile, comunicatii Internet sau cod Java (bytecode) etc. Generic, fluxurile de octeti sunt subclase ale claselor abstracte predefinite: - InputStream - pentru fluxuri de octeti de intrare si - OutputStream - pentru fluxuri de octeti de iesire.
Fluxurile de caractere reprezinta un tip special de flux de octeti, care se folosesc numai pentru date de tip text (tiparibile). Ele difera de fluxurile de octeti prin faptul ca setul de caractere Java suporta codificarea Unicode (cu doi octeti pe caracter).
Toate datele de tip text, cum ar fi fisierele text, paginile Web, sau alte formate de text, este necesar sa foloseasca fluxurile de caractere. Generic, fluxurile de caractere sunt subclase ale claselor abstracte predefinite: - Reader - pentru fluxuri de caractere de intrare si - Writer - pentru fluxuri de caractere de iesire.
3/2/2014 3
Java ofera trei fluxuri predefinite pentru operatii de I/O standard (de la tastatura, la ecranul calculatorului sau pentru erori) care sunt campuri ale clasei System inclusa in pachetul java.lang: - System.in - reprezinta intrarea standard (implicit, tastatura calculatorului); acest flux este de tip InputStream; - System.out - reprezinta iesirea standard (implicit, ecranul calculatorului); acest flux este de tip PrintStream; - System.err - reprezinta fluxul standard de iesire pentru mesaje de eroare (implicit, ecranul calculatorului); acest flux este de tip PrintStream. Dintre metodele clasei System, referitoare la fluxurile predefinite descrise mai sus, mentionam: - metoda setIn, care redirecteaza fluxul de intrare standard catre o alta sursa decat tastatura (de exemplu, un fisier pe disc); aceasta metoda are antetul: void setIn(InputStream <in>)
- metoda setOut, care redirecteaza fluxul de iesire standard catre o alta destinatie decat ecranul calculatorului (de exemplu, un fisier pe disc); aceasta metoda are antetul:
void setOut(PrintStream <out>)
3/2/2014 4
- metoda setErr, care redirecteaza fluxul de iesire standard al mesajelor de eroare catre o alta destinatie decat ecranul calculatorului (de exemplu, un fisier pe disc); aceasta metoda are antetul: void setErr(PrintStream <out>) Asocierea fluxului de intrare sau de iesire cu un filtru
Majoritatea claselor Java folosite in prezent permit realizarea de operatii de intrare/iesire mai performante prin asocierea fluxului cu un filtru, inainte de a citi sau scrie date.
Un filtru este un tip de flux care schimba modul in care se lucreaza cu un flux existent. Procedura de folosire a unui filtru pentru un flux presupune urmatorii pasi: 1. crearea (deschiderea) unui flux asociat cu sursa de date sau cu destinatia datelor; 2. crearea (deschiderea) unui flux de tip filtru asociat cu fluxul deschis la pasul 1; 3. citirea/scrierea datelor de la /in filtru si nu direct in flux.
3/2/2014 5
FileInputStream
Clasa InputStream este o clasa abstracta si din ea deriveaza toate celelalte clase care creaza fluxuri de octeti de intrare si realizeaza operatii de intrare pe aceste fluxuri. Clasa OutputStream este o clasa abstracta si din ea deriveaza toate celelalte clase care creaza fluxuri de octeti de iesire si realizeaza operatii de iesire pe aceste fluxuri. Nota: Deoarece fluxurile de intrare/iesire semnaleaza exceptia IOException la aparitia unei erori, toate operatiile legate de fluxuri se incadreaza in blocuri try catch, care sa intercepteze aceasta exceptie.
3/2/2014 6
Fluxuri nefiltrate de octeti de intrare care folosesc ca sursa un fisier Sunt folosite pentru transferul de date de la fisierele aflate pe hard-discuri, pe CDROM sau pe alte dispozitive de stocare (ce pot fi referite printr-o cale de director si un nume) catre aplicatia Java. Crearea (deschiderea) unui flux de intrare de la un fisier se realizeaza cu ajutorul constructorului clasei FileInputStream, care are forma: FileInputStream(String <sir>) unde: - <sir> - reprezinta numele, si eventual calea, fisierului; la specificarea caii fisierului trebuie sa se foloseasca doua caractere backslash pentru a nu se confunda cu o secventa escape. Daca fisierul nu poate fi deschis, atunci este lansata exceptia FileNotFoundException. De exemplu, urmatoarea instructiune deschide un flux de intrare de la fisierul test.dat: FileInputStream fis = new FileInputStream(test.dat);
3/2/2014 7
Dupa deschiderea fluxului de intrare din fisier se pot folosi metodele acestui flux pentru realizarea diverselor operatii de intrare. Descriem cateva dintre ele. Metoda read() citeste un octet din fluxul de intrare; rezultatul intors este un intreg din intervalul 0 - 255. Daca s-a detectat sfarsitul de fisier, rezultatul intors este -1. Metoda read cu trei parametrii are forma: read (byte [] <b>, int <poz_ini>, int <lungime>) unde: - <b> - un tablou de octeti in care se vor memora datele citite; - <poz_ini> - pozitia elementului din cadrul tabloului unde se va stoca primul octet de date; - <lungime> - numarul de octeti care se vor citi din fluxul de intrare repetand metoda read fara parametri. Metoda returneaza un intreg care reprezinta numarul de octeti cititi sau -1 daca, de la inceput, fluxul de intrare este la sfarsitul sau. Metoda skip avanseaza cu n pozitii (octeti) in fluxul de intrare, nedepasind bineinteles sfarsitul fluxului. Rezultatul intors de metoda este numarul de pozitii peste care s-a trecut efectiv.
3/2/2014 8
skip(long <n>)
unde : <n> - nr de octeti sariti in fluxul de intrare. Metoda available() este folosita pentru a returna numarul de octeti ce mai pot fi cititi la momentul curent din fluxul de intrare. Metoda close() inchide fluxul de intrare respectiv si elibereaza resursele sistem asociate cu acesta. De exemplu, programul CitesteFiserOcteti .java citeste octeti dintr-un flux de intrare al unui fisir cu numele test.doc. Dupa citirea ultimului octet din fisier, pentru inchiderea fluxului de intrare se foloseste metoda close(). Aceasta operatie trebuie realizata pentru a elibera resursele sistemului asociate fisierului deschis. Fisierul de intrare cu numele test.dat din care se citesc date in forma binara contine doua linii: 0123456789 Ionescu Florin Acest fisier a fost creat cu utilitarul Notepad.
3/2/2014 9
import java.io.*; public class CitesteFisierOcteti { public static void main(String [] args) { try { FileInputStream fis = new FileInputStream("test.dat"); int index = 0; int octet = fis.read(); while (octet != -1) { System.out.print(octet + " "); index++; octet = fis.read(); } fis.close(); System.out.println("\nOcteti cititi: " + index); } catch (IOException e) { System.out.println("Eroare - " + e.getMessage()); } } }
3/2/2014 10
Dupa executia programului va fi afisat fiecare octet din fisierul test.dat, urmat de numarul total de octeti cititi, ca mai jos: 48 49 50 51 52 53 54 55 56 57 13 10 73 111 110 101 115 99 117 32 70 108 111 114 105 110 Octeti cititi: 26 Observatie: Se observa ca valorile octetilor afisati sunt codurile ASCII ale caracterelor din cele doua linii existente in fisier. Fluxuri nefiltrate de octeti de iesire care folosesc ca destinatie un fisier Sunt folosite pentru transferul de date de la aplicatia Java catre fisierele aflate pe hard-discuri, pe CD-ROM sau pe alte dispozitive de stocare (ce pot fi referite printro cale de director si un nume). Crearea (deschiderea) unui flux de iesire catre un fisier se realizeaza cu ajutorul constructorului clasei FileOutputStream, care are forma: FileOutputStream(String <sir>)
unde:
- <sir> - reprezinta numele, si eventual calea, fisierului; la specificarea caii fisierului trebuie sa se foloseasca doua caractere backslash pentru a nu se confunda cu o secventa escape.
3/2/2014 11
Trebuie sa se aiba o grija deosebita atunci cand se specifica numele fisierului in care se scrie. Daca se foloseste numele unui fisier deja existent, odata cu inceperea scrierii datelor, acesta va fi sters definitiv.
Constructorul cu doi parametrii are forma: FileOutputStream(String <sir>, boolean <adauga>) unde: - <sir> - reprezinta numele, si eventual calea, fisierului; la specificarea caii fisierului trebuie sa se foloseasca doua caractere backslash pentru a nu se confunda cu o secventa escape.
- <adauga> - poate avea valoare true, caz in care se face adaugarea datelor la sfarsitul fisierului, sau poate avea valoarea false, caz in care nu se face adaugarea de date la sfarsitul fisierului ci suprascrierea datele existente; daca fisierul nu poate fi deschis, atunci este lansata exceptia FileNotFoundException.
De exemplu, urmatoarea instructiune deschide un flux de iesire catre fisierul test1.dat: FileOutputStream fis = new FileOutStream(test1.dat);
3/2/2014 12
Urmatoarea instructiune deschide un flux de iesire catre fisierul test1.dat pentru a adauga octeti la sfarsitul fisierului: FileOutputStream fis = new FileOutStream(test1.dat, true); Dupa deschiderea fluxului de iesire din fisier se pot folosi metodele acestui flux pentru realizarea diverselor operatii de iesire. Descriem cateva dintre ele.
Metoda write cu un parametru scrie un octet in fluxul de iesire. Aceasta metoda are forma:
write(int <b>) unde: <b> - variabila care contine octetul de scris in fluxul de iesire.
Metoda write cu doi parametrii scrie un tablou de octeti in fluxul de iesire si are forma:
write (byte [] <b>) unde: - <b> - specifica un tablou de octeti care va fi scris in fluxul de iesire; in fisier vor fi scrisi b.length octeti.
13
3/2/2014
Metoda write cu trei parametrii are forma: write (byte [] <b>, int <poz_ini>, int <lungime>) unde:
3/2/2014
14
import java.io.*; public class ScrieFisierOcteti { public static void main (String [] args) { int [] octeti = { 71, 73, 70, 56, 57, 97, 15, 0, 15, 0, 128, 0, 0, 111, 111, 111, 0, 0, 0, 44, 0, 0, 0, 0, 15, 0, 15, 0, 0, 2, 33, 132, 127, 161, 200, 185, 205, 84, 128, 241, 81, 35, 175, 155, 26, 228, 25, 105, 33, 102, 0, 165, 201, 145, 169, 154, 142, 112, 0, 200, 200, 0, 200, 200, 200, 200 } ; try { FileOutputStream fis = new FileOutputStream("test1.gif"); for (int i = 0; i < octeti.length; i++) fis.write(octeti[i]); fis.close(); } catch(IOException e) { System.out.println("Eroare - " + e.getMessage()); } } }
3/2/2014 15
InputStream FilterInputStream
PrintStream
3/2/2014 16
B.1 Fluxuri de octeti cu o zona tampon (buffer) Un tampon (buffer) reprezinta o zona de memorie RAM in care se pot pastra date din fluxul de intrare sau de iesire pana la momentul citirii sau scrierii lor intr-o aplicatie Java. Prin folosirea unui tampon se pot accesa (citi sau scrie) date fara a folosi sursa originala (fisierul) sau destinatia originala (fisierul) de date. Zona tampon este folosita ca o zona intermediara pentru citirea/ scrierea datelor din/in fluxul de intrare/iesire. Pentru memoria tampon se mai foloseste si termenul de memorie de lucru. Aceasta tehnica este mai eficienta intrucat utilizarea zonei tampon evita accesarea fisierului pentru fiecare citire/scriere, in acest mod micsorandu-se timpul de lucru al aplicatiei Java. Nota: Deoarece fluxurile de intrare/iesire cu tampon semnaleaza exceptia IOException la aparitia unei erori, toate operatiile legate de fluxuri se incadreaza in blocuri try catch, care sa intercepteze aceasta exceptie. Fluxuri de octeti de intrare cu o zona tampon
Un flux de intrare cu tampon poseda un tampon cu date din care se face citirea. Cand aplicatia Java citeste date, acestea sunt cautate mai intai in zona tampon si apoi in sursa originala de intrare. Fluxurile de octeti de intrare cu tampon folosesc clasa BufferedInputStream.
3/2/2014 17
Crearea (deschiderea) unui flux de intrare cu tampon se realizeaza cu ajutorul constructorilor clasei BufferedInputStream. Cand este deschis un flux de intrare cu tampon se creaza si o zona tampon, sub forma unui tablou de octeti, atasata acestuia. Constructorii clasei BufferedInputStream au una din formele: a)
BufferedInputStream(InputStream <in>)
unde: - <in> - reprezinta fluxul original de tip InputStream. Nota: Zona tampon are o lungime care este aleasa implicit (automat). b) BufferedInputStream(InputStream <in>, int <lg_buffer>) unde:
3/2/2014
Dupa deschiderea fluxului de intrare cu tampon se pot folosi metodele acestui flux pentru realizarea diverselor operatii de intrare. Descriem cateva dintre ele.
Metoda read() citeste un octet din fluxul de intrare cu tampon; rezultatul intors este un intreg din intervalul 0 - 255. Daca s-a detectat sfarsitul de fisier, rezultatul intors este -1. Metoda read cu trei parametrii are forma: read (byte [] <b>, int <poz_ini>, int <lungime>) unde: - <b> - un tablou de octeti in care se vor memora datele citite; - <poz_ini> - pozitia elementului din cadrul tabloului unde se va stoca primul octet de date; - <lungime> - numarul de octeti care se vor citi din fluxul de intrare cu tampon repetand metoda read fara parametri. Metoda returneaza un intreg care reprezinta numarul de octeti cititi sau -1 daca, de la inceput, fluxul de intrare este la sfarsitul sau.
3/2/2014 19
Metoda skip avanseaza cu n pozitii (octeti) in fluxul de intrare cu tampon si descarca n octeti din flux, nedepasind, bineinteles, sfarsitul fluxului. Rezultatul intors de metoda este numarul de pozitii peste care s-a trecut efectiv.
Metoda skip are forma: skip(long <n>) unde : <n> - nr de octeti sariti in fluxul de intrare si descarcati din fluxul de intare. Metoda available() este folosita pentru a returna numarul de octeti ce mai pot fi cititi la momentul curent atat din zona tampon, cat si din fluxul de intrare. Metoda close() inchide fluxul de intrare cu tampon si elibereaza resursele sistem asociate cu acesta. Fluxuri de octeti de iesire cu o zona tampon Un flux de iesire cu tampon poseda un tampon cu date care nu au fost inca scrise in destinatia originala a fluxului. Atunci cand datele sunt directionate intr-un flux de iesire cu tampon, continutul acestuia nu va fi transmis catre destinatie decat dupa ce zona tampon atasata s-a umplut. Fluxurile de octeti de iesire cu tampon folosesc clasa BufferedOutputStream.
3/2/2014 20
Crearea (deschiderea) unui flux de iesire cu tampon se realizeaza cu ajutorul constructorilor clasei BufferedOutputStream. Cand este deschis un flux de iesire cu tampon se creaza si o zona tampon, sub forma unui tablou de octeti, atasata acestuia. Constructorii clasei BufferedOutputStream au una din formele: a)
BufferedOuputStream(OutputStream <out>)
unde: - <out> - reprezinta fluxul de iesire de tip OutputStream. Nota: Zona tampon are o lungime care este aleasa implicit (automat). b) BufferedOutputStream(OutputStream <out>, int <lg_buffer>) unde:
3/2/2014
Dupa deschiderea fluxului de iesire cu tampon se pot folosi metodele acestui flux pentru realizarea diverselor operatii de iesire. Descriem cateva dintre ele. Metoda write cu un parametru scrie un octet in fluxul de iesire cu tampon. Aceasta metoda are forma: write(int <b>)
unde: <b> - variabila care contine octetul de scris in fluxul de iesire cu tampon; valoarea acestei variabile trebuie sa apartina intervalului 0 - 255; daca se incearca scrierea unei valori care este mai mare decat 255 va fi stocat numai restul impartirii acestei valori la 256.
Metoda write cu trei parametrii are forma: write (byte [] <b>, int <poz_ini>, int <lungime>) unde: - <b> - specifica un tablou de octeti care va fi scris in fluxul de iesire cu tampon;
- <poz_ini> - pozitia elementului din cadrul tabloului de la care se incepe scrierea in fluxul de iesire cu tampon;
- <lungime> - numarul de octeti care se vor scrie in fluxul de iesire cu tampon.
3/2/2014 22
Metoda flush() transmite (scrie) continutul zonei tampon la destinatia fluxului de iesire original chiar daca aceasta zona tampon nu s-a umplut inca. Cu ajutorul acestei metode se realizeaza golirea zonei tampon chiar daca aceasta nu s-a umplut inca. Metoda close() inchide fluxul de iesire cu tampon si elibereaza resursele sistem asociate cu acesta. Urmatorul program (IOBinarTampon.java) scrie o serie de octeti intr-un flux de iesire cu tampon asociat cu un fisier pe disc. Limita inferioara si limita superioara din seria de numere sunt specificate in doua argumente transmise prin linia de comanda, ca in exemplul urmator: java IOBinarTampon 2 30 Daca nu se transmit argumente prin linia de comanda, implicit limita inferioara este 0 iar limita superioara este 255.
Dupa scrierea in fisier, programul deschide un flux de intrare cu tampon si citeste octetii scrisi in fisier.
3/2/2014
23
import java.io.*; public class IOBinarTampon { public static void main (String [] args) { int limInf = 0; int limSup = 255; try { if (args.length > 1) { limInf = Integer.parseInt(args[0]); limSup = Integer.parseInt(args[1]); } else if(args.length > 0) limInf = Integer.parseInt(args[0]); FluxOcteti fo = new FluxOcteti(limInf, limSup); System.out.println("\nScrie: "); boolean succesScrie = fo.scrieFlux(); System.out.println("\nCiteste: "); boolean succesCiteste = fo.citesteFlux(); } catch(NumberFormatException nfe) { System.out.println("Eroare: " + "Nu ati introdus un numar intreg"); } } }
3/2/2014 24
class FluxOcteti { private int inceput = 0; private int sfarsit = 255; public FluxOcteti(int inceput, int sfarsit) { this.inceput = inceput; this.sfarsit = sfarsit; } boolean scrieFlux() { try { BufferedOutputStream fluxTampon = new BufferedOutputStream( new FileOutputStream("numere.dat")); for (int i = inceput; i <= sfarsit; i++) { fluxTampon.write(i); System.out.print(" " + i); } fluxTampon.close(); return true; } catch(IOException e) { System.out.print("Eroare: " + e.getMessage()); return false; } }
3/2/2014 25
boolean citesteFlux() { try { BufferedInputStream fluxTampon = new BufferedInputStream( new FileInputStream("numere.dat")); int i = 0; do { i = fluxTampon.read(); if (i != -1) System.out.print(" " + i); } while (i != -1); fluxTampon.close(); return true; } catch(IOException e) { System.out.print("Eroare: " + e.getMessage()); return false; } }
}
3/2/2014
26
Observatie: Aplicatia Java prezentata mai sus poate primi unul sau doua argumente atunci cand este lansata. Modul de transmitere a unor argumente la aplicatii Java depinde de platforma pe care se executa Java. In Windows si Unix se pot transmite argumente prin intermediul liniei de comanda.
Argumentele trebuie adaugate la executie dupa numele programului si daca sunt mai multe decat unul, atunci argumentele sunt separate prin spatii.
In cadrul aplicatiei Java, argumentele din linia de comanda sunt preluate de metoda main() sub forma unui tablou de siruri:
3/2/2014
27
B2. Fluxuri filtrate cu date de tipuri primitive Clasele DataInputStream si DataOutputStream ofera, ca facilitate suplimentara, posibilitatea ca fluxurile sa nu mai fie privite strict la nivel de octet, ci ca succesiuni de date primitive. Prin aceasta, datele vor fi scrise in fluxul de iesire intr-un format independent de modul de reprezentare al datelor in sistemul pe care se lucreaza. Constructorul clasei DataInputStream creaza un nou flux de intrare ce suprapune pe cel existent primit ca argument. Constructorul are forma: DataInputStream(InputStream <in>) unde:
- <in> - specifica fluxul de intrare existent, de exemplu, un flux de intrare cu tampon sau un flux de intrare din fisier.
Constructorul clasei DataOutputStream creaza un nou flux de iesire ce suprapune pe cel existent primit ca argument. Constructorul are forma:
DataOutputStream(OutputStream <out>) unde:
- <out> - specifica fluxul de iesire existent, de exemplu, un flux de iesire cu tampon sau un flux de iesire in fisier. Deoarece fluxurile filtrate de intrare/iesire cu date de tipuri primitive semnaleaza exceptia IOException la aparitia unei erori, toate operatiile legate de fluxuri se incadreaza in blocuri try catch, care sa intercepteze aceasta exceptie.
3/2/2014 28
Urmatoarea lista prezinta metodele de citire si de scriere ce pot fi folosite pentru fluxurile de tipul DataInputStream, si respectiv de tipul DataOutputStream: - readBoolean(); writeBoolean(boolean <v>); - readChar(); writeChar(char <v>); - readDouble(); writeDouble(double <v>);
Fiecare dintre metodele de scriere prezentate incearca sa scrie un numar de octeti egal cu lungimea pe care sunt reprezentate tipurile respective indicate in numele metodei. De exemplu, metoda writeBoolean() scrie intr-un octet valoarea 1 sau valoarea 0, dupa cum parametrul <v> este true sau false.
3/2/2014 29
Observatii:
1. Datele citite folosind metodele clasei DataInputStream trebuie sa fi fost scrise in fisier cu metodele complementare ale clasei DataOutputStream. 2. Nu toate metodele de citire dintr-un flux de tip DataInputStream returneaza o valoare ce poate indica faptul ca s-a ajuns la sfarsitul fluxului. In astfel de cazuri se semnaleaza exceptia EOFException care indica faptul ca s-a ajuns la sfarsitul fluxului de intrare. Urmatorul program (IODataTampon.java) scrie o serie de valori de tip float intr-un flux de iesire DataOutputStream cu tampon asociat cu un fisier pe disc. Limita inferioara si limita superioara din seria de numere reale sunt specificate in doua argumente transmise prin linia de comanda, ca in exemplul urmator: java IOBinarTampon 2 30 Daca nu se transmit argumente prin linia de comanda, implicit limita inferioara este 0 iar limita superioara este 255. Dupa scrierea in fisier, programul deschide un flux de intrare cu tampon si citeste datele de tip float scrise in fisier.
3/2/2014 30
import java.io.*; public class IODataTampon { public static void main (String [] args) { float limInf = 0; float limSup = 255; try { if (args.length > 1) { limInf = Float.parseFloat(args[0]); limSup = Float.parseFloat(args[1]); } else if(args.length > 0) limInf = Float.parseFloat(args[0]); FluxDatePrimitive fd = new FluxDatePrimitive(limInf, limSup); boolean succesScrie = fd.scrieFlux(); System.out.println("\nCiteste: "); boolean succesCiteste = fd.citesteFlux(); } catch(NumberFormatException nfe) { System.out.println("Eroare: " + "Nu ati introdus un numar real"); } } }
3/2/2014 31
class FluxDatePrimitive { private float inceput = 0; private float sfarsit = 255; public FluxDatePrimitive(float inceput, float sfarsit) { this.inceput = inceput; this.sfarsit = sfarsit; } boolean scrieFlux() { try { DataOutputStream fluxDate = new DataOutputStream( new BufferedOutputStream(new FileOutputStream("numere.dat"))); for (float i = inceput; i <= sfarsit; i+=0.5) fluxDate.writeFloat(i); fluxDate.close(); return true; } catch(IOException e) { System.out.print("Eroare: " + e.getMessage()); return false; } }
3/2/2014
32
boolean citesteFlux() { try { DataInputStream fluxDate = new DataInputStream( new BufferedInputStream(new FileInputStream("numere.dat"))); float i = 0; try { while (true) { i = fluxDate.readFloat(); System.out.print(" " + i); } } catch(EOFException eof) { fluxDate.close(); } return true; } catch(IOException e) { System.out.print("Eroare: " + e.getMessage()); return false; } } }
3/2/2014 33
Aplicatia prezentata este un exemplu de suprapunere a mai multor filtre peste un flux original de tip FileInputStream. Fluxul filtrat este construit in trei etape: - se creaza un flux de iesire in fisier, asociat cu fisierul numere.dat; - se asocieaza fluxului de fisier un flux de iesire filtrat cu tampon;
3/2/2014
34
In plus, fluxul PrintStream da posibilitatea (optional) de a goli automat zona tampon dupa ce a fost scris un tablou de octeti sau un octet egal cu \n. Metodele acestei clase nu semnaleaza niciodata exceptia IOException. Fluxul System.out, pe care l-am folosit aproape in toate lectiile de pana acum pentru afisarea mesajelor la ecranul calculatorului, este de fapt un flux de tip PrintStream. Prezentam doi dintre constructorii acestei clase: PrintStream(OutputStream <out>) PrintStream(OutputStream <out>, boolean <auto_golire>) unde: - <out> - specifica fluxul de iesire existent; <auto_golire> - specifica daca se goleste automat zona tampon dupa ce a fost scris un tablou de octeti sau un octet egal cu \n (daca valoarea este true).
3/2/2014
35
Mentionam cateva metode ale acestei clase: - print (String <s>) - print (char <c>) - print (boolean <b>) - print (char <c>) - print (int <i>) - print (long <l>) - print (float <f>) - print (double <d>) Pentru fiecare metoda print exista si perechea ei println, care adauga caracterul \n in fluxul de iesire.
In plus, exista si metoda println fara parametrii, care scrie doar caracterul de sfarsit de linie \n.
Metodele print si println scriu argumentul lor intr-un format de tip text si anume identic cu cel produs de apelurile metodei String.valueOf(x).
Un flux PrintStream nu are ca destinatie numai ecranul calculatorului ci orice destinatie de flux, inclusiv un fisier text ASCII. De exemplu, urmatoul program (PrintStreamFile.java) afiseaza un String, un intreg si un numar in virgula mobila intr-un fisier, print.txt.
3/2/2014 36
import java.io.*; public class PrintStreamFile { public static void main(String [] args) { double nr1 = 234.5; int nr2 = 120; try { PrintStream ps = new PrintStream(new FileOutputStream("print.txt")); ps.println ("Date pentru testarea fluxului PrintStream"); ps.print(nr1); ps.print(' '); ps.print(nr2); ps.println(); ps.println(Math.PI); ps.close(); } catch(IOException e) { System.out.println("Eroare la scrierea fisierului: " + e.getMessage()); } } }
3/2/2014
37
BufferedReader
InputStreamReader
LineNumberReader
3/2/2014
FileReader
38
Clasa Reader este o clasa abstracta si din ea deriveaza toate celelalte clase care creaza fluxuri de caractere de intrare si realizeaza operatii de intrare pe aceste fluxuri. Nota: Deoarece fluxurile de intrare semnaleaza exceptia IOException la aparitia unei erori, toate operatiile legate de fluxuri se incadreaza in blocuri try catch, care sa intercepteze aceasta exceptie. Este indicat sa folosim clasa Reader pentru lucru cu text si nu fluxuri de octeti. A.1 Fluxuri nefiltrate de caractere de intrare care folosesc ca sursa un fisier
Sunt folosite pentru transferul de date de la fisierele aflate pe hard-discuri, pe CDROM sau pe alte dispozitive de stocare (ce pot fi referite printr-o cale de director si un nume) catre aplicatia Java. Principala clasa folosita pentru citirea de fluxuri de caractere dintr-un fisier este FileReader. Aceasta clasa mosteneste clasa InputStreamReader, care citeste un flux de octeti si ii converteste in valori intregi corespunzatoare caracterelor Unicode.
3/2/2014
39
Crearea (deschiderea) unui flux de intrare de la un fisier se realizeaza cu ajutorul constructorului clasei FileReader, care are forma: FileReader(String <sir>) unde: - <sir> - reprezinta numele, si eventual calea, fisierului; la specificarea caii fisierului trebuie sa se foloseasca doua caractere backslash pentru a nu se confunda cu o secventa escape. Daca fisierul nu poate fi deschis, atunci este lansata exceptia FileNotFoundException. De exemplu, urmatoarea instructiune deschide un flux de intrare de la fisierul test.doc: FileReader document = new FileReader(test.doc);
3/2/2014
40
Dupa deschiderea fluxului de caractere de intrare din fisier se pot folosi metodele acestui flux pentru realizarea diverselor operatii de intrare. Descriem cateva dintre ele.
Metoda read() citeste un caracter din fluxul de intrare; rezultatul intors este un intreg din intervalul 0 - 65535. Daca s-a detectat sfarsitul de fisier, rezultatul intors este -1.
Nota: Deoarece metoda read() a unui flux de caractere returneaza o valoare intreaga, trebuie sa se converteasca explicit prin cast aceasta valoare inainte de a o afisa sau de a o salva intr-un tablou de caractere. Fiecare caracter poseda un cod numeric care reprezinta pozitia sa in setul de caractere Unicode. Valoarea intreaga citita din flux reprezinta chiar acest cod numeric. Metoda skip avanseaza cu n pozitii (caractere) in fluxul de intrare, nedepasind bineinteles sfarsitul fluxului. Rezultatul intors de metoda este numarul de pozitii peste care s-a trecut efectiv. Metoda skip are forma: skip(long <n>)
unde :
<n> - nr de caractere sarite in fluxul de intrare. Metoda ready() specifica daca acest flux de caractere este disponibil pentru a fi citit. Un flux de caractere dintr-un fisier este disponibil pentru a fi citit daca zona tampon de intrare nu este goala (in caz ca ea exista) sau daca exista octeti disponibili de a fi cititi de la fluxul de octeti de tip InputStreamReader. Metoda close() inchide fluxul de intrare respectiv si elibereaza resursele sistem asociate cu acesta.
3/2/2014 42
Fluxurile de caractere cu o zona tampon (buffer) permit utilizarea unei zone tampon pentru cresterea eficientei operatiilor de citire.
Fluxurile de caractere de intrare cu tampon folosesc clasa BufferedReader. Crearea (deschiderea) unui flux de caractere cu tampon se realizeaza cu ajutorul constructorilor clasei BufferedReader. Constructorii clasei BufferedReader au una din formele: a) BufferedReader(Reader <in>) unde:
unde:
read (char [] <c>, int <poz_ini>, int <lungime>) , asemanatoare celor descrise pentru clasa FileReader.
Metodele skip(), ready() si close() sunt asemanatoare celor descrise pentru clasa FileReader. Programul urmator (CitesteSiruri.java) citeste doua siruri de caractere de la tastatura si le stocheaza intr-un tablou de caractere de lungime 20. Daca dupa citirea primului sir, in zona tampon mai exista caractere necitite (ceea ce inseamna ca s-a introdus un sir de lungime mai mare de 20) atunci acestea vor fi sarite din fluxul de intrare pentru a permite eliberarea zonei tampon si citirea de la tastatura a celui de al doilea sir.
import java.io.*; class CitesteSiruri { public static void main(String[] args) { char[] caractere1 = new char[20]; char[] caractere2 = new char[20]; for (int i=0; i <=19; i++) caractere1[i] = ' '; for ( int i=0; i <=19; i++) caractere2[i] = ' ';
3/2/2014 44
try { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println ("Introduceti primul sir"); br.read(caractere1, 0, 20); String sir1 = new String(caractere1); System.out.println(sir1); while (br.ready() ) br.skip (1); System.out.println ("Introduceti al doilea sir"); br.read(caractere2, 0, 20); String sir2 = new String(caractere2); System.out.println(sir2); boolean rezultat = false; rezultat = sir1.equals(sir2); if (rezultat ==true) System.out.println ("siruri egale"); else System.out.println ("siruri diferite"); } catch(IOException e) { System.out.println ("Eroare la sirul citit" + e.getMessage()); } } }
3/2/2014 45
Metoda readLine() citeste din fluxul de intrare o linie de text. Metoda returneaza un obiect de tip String care contine linia de text citita din flux , fara a include si caracterul (sau caracterele) care reprezinta sfarsitul de linie. Daca se ajunge la sfarsitul fluxului, valoarea sirului returnat va fi null.
Sfarsitul de linie este indicat astfel:
Programul urmator (CitesteLiniiFisier.java) ilustreaza modul de citire linie cu linie dintr-un fisier care contine instructiuni Java (numit CitesteLiniiFisier.java), folosind un flux de caractere cu zona tampon.
3/2/2014 46
import java.io.*; public class CitesteLiniiFisier { public static void main (String [] args) { try { BufferedReader fisier = new BufferedReader( new FileReader("CitesteLiniiFisier.java")); boolean eof = false; while(!eof) { String linie = fisier.readLine(); if (linie == null) eof = true; else System.out.println(linie); } fisier.close(); } catch(IOException e) { System.out.println("Eroare: " + e.getMessage()); } } }
3/2/2014 47
A.3 Fluxuri filtrate de caractere de intrare cu o zona tampon care tin evidenta numerelor de linie Fluxurile de caractere de intrare cu tampon care tin evidenta numerelor de linie dintrun fisier folosesc clasa LineNumberReader. Acest filtru al fluxului de intrare urmareste numarul de linie pe masura citirii din fluxul de intrare. Crearea (deschiderea) unui flux de caractere cu tampon care tin evidenta numerelor de linie se realizeaza cu ajutorul constructorilor clasei LineNumberReader. Constructorii clasei LineNumberReader au una din formele: a) LineNumberReader(Reader <in>) - <in> - reprezinta fluxul original de tip Reader. Nota: Zona tampon are o lungime care este aleasa implicit (automat). b) unde:
unde:
48
Metodele pentru citirea, inchiderea, testarea unui flux de intrare cu tampon sunt mostenite de la clasa BufferedReader si ele au fost prezentate deja. In plus, aceasta clasa ofera metoda getLineNumber() care este folosita pentru a obtine numarul liniei curente din fluxul de intrare atunci cand acesta este citit cu metoda readLine(). Metoda returneaza un intreg care reprezinta numarul liniei curente din flux. Dintr-un fisier se poate citi o intreaga linie de text si se poate tine evidenta numerelor citite daca se foloseste un flux de caractere cu tampon de tip LineNumberReader suprapus peste un flux de tip FileReader. Programul urmator (CitesteLiniiFisier.java) afiseaza numerele liniilor citite dintr-un fisier care contine instructiuni Java (numit CitesteLiniiFisier1.java), folosind un flux de caractere cu zona tampon tip LineNumberReader.
3/2/2014
49
import java.io.*; public class CitesteLiniiFisier1 { public static void main (String [] args) { try { LineNumberReader fisier = new LineNumberReader(new FileReader("CitesteLiniiFisier1.java")); boolean eof = false; while(!eof) { String linie = fisier.readLine(); if (linie == null) eof = true; else System.out.println(fisier.getLineNumber() + " " + linie); } fisier.close(); } catch(IOException e) { System.out.println("Eroare: " + e.getMessage()); } } }
3/2/2014 50