You are on page 1of 0

62

2. INTRRI/IEIRI (LOCALE).
PACHETUL JAVA.IO
2.1. Acces prin stream i acces random
Operaiile de intrare/ieire n limbajul Java, ca i n alte limbaje se
efectueaz att n acces secvenial, ct i n acces direct. n aceast seciune
avem n vedere doar operaiile de schimb locale, n cadrul aceluiai sistem de
calcul, deci ntre memoria intern i dispozitivele periferice (hard-discuri,
dischete, CD-uri, benzi streamer, imprimante, tastaturi, monitoare etc.) conec-
tate la sistem.
Terminologia Java numete stream un mediu de I/O n care accesul este
strict secvenial, fie numai n citire, fie numai n scriere. Din acest punct de
vedere distingem stream de intrare (InputStream) din care se poate numai citi
(transfera octei de la periferic sau fiier n memoria intern) i stream de ieire
(OutputStream) n care se poate doar scrie (transfer din memoria intern spre
periferic - fiier). O operaie I/O cu un stream transfer un numr oarecare de
octei consecutivi. Operaia urmtoare va transfera, n acelai sens, un numr de
octei consecutivi dintre cei care urmeaz. Numrul de octei transferai ntr-o
operaie este independent de numrul octeilor transferai n operaia precedent
(operaiile precedente). Se observ c, cel puin la acest nivel, nu este utilizat
conceptul de articol [17]. De fapt, gestiunea la nivel de articol rmne pe seama
programatorului, care poate s decupeze fiierul, privit ca ir de octei
succesivi, n entiti de prelucrare numite articol.
Pachetul java.io individualizeaz trei stream-uri speciale:

stream-ul standard de intrare asociat de regul tastaturii, dar care
poate fi redirectat prin sistemul de operare al mainii gazd [17];
stream-ul standard de ieire asociat de regul monitorului sau unei
ferestre din el;
stream-ul standard de erori asociat de regul tot monitorului sau
unei ferestre a lui.

Aceste trei fiiere sunt fiiere text. Toate trei, sau numai unele dintre ele
pot fi redirecionate i eventual conectate n pipe prin metode specifice
sistemului de operare al mainii gazd [17]. Stream-urile standard sunt definite

63
n clasa System, prin variabilele System.in, System.out,
System.err.
Stream-urile care nu sunt cele standard folosesc ca i surs de intrare i
ieire nu numai fiiere, ci i tablouri, zone tampon ntre procese (pipe), sau orice
altceva care poate s conin date. Toate aceste stream-uri sunt implementate n
pachetul java.io.
Orice stream se deschide automat la creare. Stream-ul se nchide cu
metoda close sau se nchide automat cnd obiectul nu mai este utilizat i este
colectat de thread-ul garbage collection.
Accesul direct este posibil numai la fiiere rezidente pe suporturi adresa-
bile. Pachetul java.io ofer posibilitatea de a accesa, att n citire ct i n
scriere, iruri arbitrare de octei, caractere, sau orice fel de date primitive,
plasate oriunde n fiier. Acestea, dac nu se fac n/din locul rmas de la accesul
precedent, trebuie precedate de o operaie de poziionare - seek -.
2.2. Gestiunea structurii de fiiere: clasa File
Aceast clas furnizeaz o modalitate de gestiune a structurii de fiiere
independent de platform. Astfel, se furnizeaz lista tuturor intrrilor dintr-un
director. Exist metode care controleaz existena unui fiier sau director,
dreptul de a fi citit sau de a se scrie n el. Furnizeaz tipul, lungimea, data i ora
ultimei modificri. Permite crearea de directori, redenumete fiiere i directori,
terge fiiere i directori. Constantele definite n aceast clas sunt separatorii
separator, separatorChar, utilizai n specificarea cilor: / pe
platforme Unix, \ pe platforme Microsoft, furnizai ca string sau ca i caracter.
De asemenea, constantele
pathSeparator, pathSeparatorChar,
prin care se specific simbolul care separ doi directori ntr-o constant sistem
PATH: caracterul : pentru platforme Unix, sau ; pentru platforme Microsoft.
Dei nu face parte din clasa File, credem c aici este momentul s
indicm cum se poate obine, dependent de platform, separatorul de linii ntr-
un fiier text. Este vorba de apelul
System.getProperty(line.separator),
care ntoarce ntr-un string fie caracterul linie nou (LF sau n notaie C-Java
\n) pentru platformele Unix, fie succesiunea retur de car linie nou (CR LF
sau n notaie C-Java \r\n) pentru platforme Microsoft. n acelai spirit,
constantele de mai sus pot fi obinte i prin intermediul apelurilor:
System.getProperty(file.separator),
System.getProperty(path.separator)

64
Primul grup de metode care ntorc boolean indic dac fiierul are sau nu
calitatea invocat.
getName ntoarce numele fiierului fr numele directorilor din calea
spre el. getParent ntoarce numele directorului din specificarea fiierului
dac s-a furnizat specificarea lui, sau null dac fiierul este specificat din
directorul curent. getPath ntoarce directorul i numele fiierului, iar
getAbsolutePath d specificarea complet, ncepnd de la rdcin.
length ntoarce lungimea fiierului. lastModified ntoarce mo-
mentul ultimei modificri. Specificarea acestui timp nu are o structur anume ci
este un simplu ir de bii care formeaz un ntreg ce poate fi comparat cu ali
timpi de la alte fiiere.
list ntoarce rezumatul directorului, eventual numai acele fiiere care
satisfac o specificare generic [17].
Ultimul grup de metode execut operaii specifice: creare de director,
tergere sau renumire de fiiere sau directori. Ele confirm prin boolean-ul
ntors dac operaia s-a desfurat normal sau nu.
Practic, orice clas care opereaz cu fiiere utilizeaz clasa File. Toate
programele pe care le vom prezenta n seciunile urmtoare vor conine exemple
de utilizare a acestei clase.
2.3. Citiri i scrieri
2.3.1. Principalele metode pentru citire
Operaia de citire presupune transferul unor octei succesivi de pe un
mediu extern n memoria intern. n funcie de gradul de inteligen al unei
operaii de citire, aceste operaii se pot clasifica n trei grupe:

1. citire binar a unui ir de octei, fr interpretarea coninutului sau
numrului acestora;
2. citire binar a unui numr fixat de octei, interpretai ca reprezen-
tnd un tip de dat elementar: ntreg, flotant, boolean etc.;
3. citire text i conversia lui n reprezentarea intern a unui tip de dat
elementar: ntreg, flotant, boolean etc.

Evident, aceast clasificare este valabil i la alte limbaje, ca i la diverse
sisteme care efectueaz operaii de intrare/ieire. Pentru Java, fiecare clas care
are metode de citire include cel puin una dintre aceste grupe.
S vedem concret care sunt metodele oferite de Java, cum funcioneaz
i n ce clase apar ele. Precizm c toate metodele pot genera excepia
IOException n cazul unor erori de transfer. Metodele care transfer tablouri

65
pot declana i excepia EOFException, dac pe parcursul schimbului se
depete sfritul de fiier.
2.3.1.1. Metode de citire binar fr interpretare
Exist dou astfel de metode i ele poart numele read. Prototipurile lor
sunt urmtoarele:

public int read(byte[] b) throws IOException, EOFException;
public int read(byte[] b, int inceput, int lungime)
throws IOException, EOFException;

Citirea cu read rmne n ateptare pn cnd citete cel puin un octet.
Octeii citii sunt depui, n ordine, n tabloul b. n primul caz se vor citi
maximum b.length octei, iar n al doilea caz maximum lungime octei
care vor fi depui n b ncepnd cu poziia inceput. ntregul ntors indic
numrul de octei efectiv citii.
Aceste metode se ntlnesc n clasa InputStream i n toi descen-
denii acesteia. De asemenea, clasa RandomAccessFile conine aceste
metode. n clasa BufferedReader metoda opereaz cu tablouri de caractere
n loc de bytes.
2.3.1.2. Metode de citire binar cu interpretare
Acestea citesc o succesiune fixat de octei succesivi pe care i interpre-
teaz ca reprezentnd un anumit tip de dat elementar. Prototipurile ctorva
dintre aceste metode sunt:

public final boolean readBoolean() throws IOException;

public final byte readByte() throws IOException;

public final char readChar() throws IOException;

public final double readDouble() throws IOException;
public final float readFloat() throws IOException;

public final int readInt() throws IOException;
public final long readLong() throws IOException;
public final short readShort() throws IOException;
public final int readUnsignedByte() throws IOException;
public final int readUnsignedShort() throws IOException;

public final String readLine() throws IOException;
public final String readUTF() throws IOException;


66
public final void readFully(byte[] b)
throws IOException, EOFException;
public final void readFully(byte[] b, int inceput, int lungime)
throws IOException, EOFException;

Primele metode citesc atia octei ci sunt necesari pentru a interpreta
reprezentarea intern Java a tipului de date respectiv. Metodele
readUnsignedByte i readUnsignedShort citesc cte un ntreg fr
semn i ntorc un int, deoarece Java nu opereaz cu ntregi fr semn.
readLine citete caractere pn cnd ntlnete un separator de linii
(marcat prin \n, \r sau succesiunea \r\n). Rezultatul ntors este un
String. Separatorul de linii nu este ntors n string, dar pointerul curent n
fiier trece peste separator. Metoda este specific doar BufferedReader i
RandomAccessFile.
readUTF citete un string de text Unicode reprezentat n codul UTF-8,
o variant ASCII a reprezentrii Unicode.
n fine, metodele readFully sunt extrem de utile mai ales n progra-
marea distribuit i n timp real. Prin ele se solicit citirea unui numr de octei
care vor fi depui n tablou sau partea de tablou specificat. Spre deosebire de
read, aici apelul rmne blocat pn cnd se transfer exact numrul de octei
solicita.
Metodele de citire din aceast grup se ntlnesc la clasele terminale din
structura pachetului java.io. n particular, aceste metode se ntlnesc la
clasele DataInputStream i RandomAccessFile, cu excepia lui
readLine, care este definit doar la BufferedReader.
2.3.1.3. Citire text i conversie
Nu exist metode de citire text i conversie. Deci, spre deosebire de C i
C++, unde exist funciile din grupul scanf, aici nu exist metode care s
citeasc un text i s-l converteasc n reprezentarea intern a unui numr.
Pentru a putea efectua totui astfel de operaii, se citete mai nti textul
ca un String, dup care se folosesc pentru conversie metodele
Integer.parseInt, Long.parseLong, Double.parseDouble
etc. Programul 1.7 (Distanta.java) ofer un astfel de exemplu.
2.3.2. Principalele metode de scriere
Seciunea de fa are multe elemente de similitudine cu seciunea
precedent, fiind ntr-un fel duala acesteia.


67
Operaia de scriere presupune transferul unor octei succesivi din
memoria intern pe un mediu extern. n funcie de gradul de inteligen al
unei astfel de operaii, distingem trei grupe:

1. scriere binar a unui ir de octei, fr interpretarea coninutului
sau numrului acestora;
2. scriere binar a unui numr fixat de octei, care reprezint un tip de
dat elementar: ntreg, flotant, boolean etc.;
3. conversie din reprezentarea intern i scriere text a unui tip de dat
elementar: ntreg, flotant, boolean etc.

Toate metodele pot genera excepia IOException n cazul unor erori
de transfer.
2.3.2.1. Metode de scriere binar fr interpretare
Exist dou astfel de metode i ele poart numele write. Prototipurile
lor sunt urmtoarele:

public void write(byte[] b) throws IOException;
public void write(byte[] b, int inceput, int lungime)
throws IOException;

Octeii sunt preluai, n ordine, din tabloul b. n primul caz se vor scrie
b.length octei, iar n al doilea caz lungime octei.
Aceste metode se ntlnesc n clasa OutputStream i n toi descen-
denii acesteia. De asemenea, clasa RandomAccessFile conine aceste
metode.
2.3.2.2. Metode de scriere binar cu interpretare
Acestea scriu octeii succesivi care conin reprezentarea unui anumit tip
de dat elementar. Prototipurile acestor metode sunt urmtoarele:

public final void writeBoolean(boolean v) throws IOException;

public final void writeByte(int v) throws IOException;
public final void writeBytes(String v) throws IOException;

public final void writeChar(int v) throws IOException;
public final void writeDouble(double v) throws IOException;
public final void writeFloat(float v) throws IOException;

public final void writeInt(int v) throws IOException;
public final void writeLong(long v) throws IOException;
public final void writeShort(short v) throws IOException;

68
public final void writeChars(String v) throws IOException;
public final void writeUTF(String v) throws IOException;

Metodele de citire din aceast grup se ntlnesc la clasele terminale din
structura pachetului java.io. n particular, aceste metode se ntlnesc la
clasele DataOutputStream i RandomAccessFile.
2.3.2.3. Metode de conversie i scriere text
Aceste metode sunt grupate n clasa PrintStream. Le vom prezenta
totui aici, pentru a ncheia cele spuse despre operaiile de scriere.
Metodele print i println preiau reprezentrile interne ale tipurilor
de date elementare, le convertesc n forme standard de reprezentri externe sub
form de text i le afieaz. Metodele print afieaz numai aceste repre-
zentri, pe cnd metodele println adaug i afieaz dup acestea un sfrit
de linie. Prototipurile acestor metode sunt urmtoarele:

public void print(boolean v);

public void print(char v);

public void print(double v);
public void print(float v);

public void print(int v);
public void print(long v);

public void print(char[] v);
public void print(String v);
public void print(Object v);

public syncronized void println();

public syncronized void println(boolean v);

public syncronized void println(char v);

public syncronized void println(double v);
public syncronized void println(float v);

public syncronized void println(int v);
public syncronized void println(long v);

public syncronized void println(char[] v);
public syncronized void println(String v);
public syncronized void println(Object v);

Uneori este util obinerea unui string cu reprezentarea extern a unei
date i nu neaprat afiarea acestei reprezentri. Este deci de dorit ceva similar

69
funciei sprintf din C. n acest scop se vor putea folosi metodele
String.valueOf(). n programele care urmeaz vom da exemple de utili-
zare a acestei metode.
n ceea ce privete exemplele de utilizare a metodelor print i
println, practic toate exemplele de programe Java care folosesc stream-urile
standard de ieire i de erori le apeleaz.
2.4. Exemple de programe
care execut operaii I/O
Exemplele care urmeaz prezint unele scenarii mai frecvente de
utilizare a I/O. n unele dintre programe vom utiliza i alte clase dect cele
prezentate mai sus, dar vom explica ceea ce s-a folosit.
2.4.1. Exemple simple de I/O
2.4.1.1. Cteva scenarii tipice
Programul 2.1 [37] prezint cinci situaii tipice de folosire a operaiilor
I/O.

import java.io.*;

public class IODemo {

public static void main(String[] args) {
try {
// 1. Citirea din intrare, linie cu linie,
// cu numele fisierului dat la linia de comanda:
BufferedReader in1 =
new BufferedReader(new FileReader(args[0]));
String s, t = new String();
while((s = in1.readLine())!= null)
t += s + System.getProperty("line.separator");
in1.close();

// 2. Citire o linie de la intrarea standard
BufferedReader in2 =
new BufferedReader(new InputStreamReader(System.in));
System.out.print("Da o linie:");
System.out.println(in2.readLine());

// 3. Intrare din memorie
StringReader in3 = new StringReader(t);
int c;

70
while((c = in3.read()) != -1)
System.out.print((char)c);

// 4. Salvare / refacere date
DataOutputStream out4 =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("Data.txt")));
out4.writeDouble(Math.PI);
out4.writeBytes("Acesta este PI");
out4.close();
DataInputStream in4 =
new DataInputStream(
new BufferedInputStream(
new FileInputStream("Data.txt")));
BufferedReader in4br =
new BufferedReader(
new InputStreamReader(in4));
// Trebuie folosit DataInputStream pentru date:
System.out.println(in4.readDouble());
// Se poate folosi readLine():
System.out.println(in4br.readLine());

// 5. RandomAccessFiles
RandomAccessFile rf =
new RandomAccessFile("rtest.dat", "rw");
for(int i = 0; i < 10; i++)
rf.writeDouble(i*1.414);
rf.close();
rf = new RandomAccessFile("rtest.dat", "rw");
rf.seek(5*8);
rf.writeDouble(47.0001);
rf.close();
rf = new RandomAccessFile("rtest.dat", "r");
for(int i = 0; i < 10; i++)
System.out.println(
"Pozitia " + i + ": " +
rf.readDouble());
rf.close();
} // try
catch(Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
} // catch
} // IODemo.main

} // IODemo
Programul 2.1. IODemo.java

Prima situaie reprezint citirea, linie cu linie, dintr-un fiier text al crui
nume este dat ca parametru n linia de comand. Folosind obiectul in1 se

71
citete linie cu linie din fiierul dat la intrare, iar string-ul t va conine toate
liniile citite, una dup alta.
Situaia a doua cere o linie de la intrarea standard, iar apoi, ntr-un
singur apel, prin intermediul obiectului in2 citete linia dat de la intrarea
standard i o tiprete la ieirea standard.
Situaia a treia creeaz, plecnd de la string-ul t din prima situaie,
obiectul in3 care este un StringReader. Din acesta se citete apoi caracter
cu caracter i se afieaz la ieirea standard.
Situaia a patra realizeaz salvarea i refacerea de date eterogene, ntr-
un fiier Data.txt. n acest scop se creeaz mai nti un obiect de ieire
out4 plecnd de la fiierul de salvare. n acest fiier se scrie mai nti un
numr flotant dup care un ir de bytes. Apoi se creeaz obiectele de intrare
in4 (un DataInputStream) i in4br (un BufferedReader), ambele
referindu-se la acelai fiier n care s-a salvat. Se citesc apoi datele salvate, mai
nti numrul florant folosind in4, dup care o linie folosind in4br. Evident,
aceste citiri respect ordinea elementelor scrise.
Situaia a cincea exemplific folosirea clasei RandomAccessFile,
prin intermediul obiectului rf. Mai nti se scriu n fiier 10 numere flotante
duble. Apoi fiierul se nchide, se redeschide, se cere poziionarea la mijlocul
lui, dup care se scrie un alt numr flotant dublu peste cel de-al 5-lea scris
anterior. n final se redeschide fiierul numai pentru citire i se afieaz cele 10
numere existente n fiier.
2.4.1.2. Rezumatul unui director
n cele ce urmeaz este prezentat un program care efectueaz rezumatul
unui director. Dac n linia de comand se d un nume, atunci programul
consider c acesta este numele directorului al crui rezumat este dorit. n caz
contrar se va afia rezumatul directorului curent. Sursa este prezentat n
programul 2.2.

import java.io.*;

public class RezumatDirector {

public static void main(String[] a) {
try {
File path = new File((a.length==0)?".":a[0]);
String[] list = path.list();
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);

72
} // try
catch(Exception e) {
e.printStackTrace();
} // catch
} // RezumatDirector.main

} // RezumatDirector
Programul 2.2. RezumatDirector.java
2.4.1.3. Tiprirea numerelor cu format
Java 1.4 ofer o mare varietate de posibiliti pentru tiprirea numerelor.
Noi oferim doar un exemplu, iar cititorul interesat poate consulta specificaiile
claselor java.text.NumberFormat i java.util.Locale pentru
detalii. Programul 2.3 prezint exemple de tiprire a numerelor cu format.

import java.io.*;
import java.text.*;
import java.util.*;

public class PrintFormat {

public static void main(String a[]) throws Exception {
double pi = Math.PI, e = Math.E;
System.out.println("PI= "+pi+" e= "+e);
NumberFormat nf = new DecimalFormat("##0.##");
System.out.println("PI= "+nf.format(pi)+" e= "+nf.format(e));
} // PrintFormat.main

} // PrintFormat
Programul 2.3. PrintFormat.java

Rezultatul execuiei va fi:
PI= 3.141592653589793 e= 2.718281828459045
PI= 3,14 e= 2,72
Caracterele '#' i '0' din format indic poziia unei cifre. n cazul
'#' dac cifra este un zerou nesemnificativ atunci acesta se nlocuiete cu un
spaiu. Dac n format apare '0', atunci apare cifra zero, chiar dac acesta
este unul nesemnificativ. Caracterul '.' din format indic marca zecimal. n
forma cea mai simpl se pune marca specific local rii n care se ruleaz
JVM (n cazul nostru Romania). Pentru modificarea acestui marcaj, se poate
consulta documentaia clasei Locale.


73
2.4.2. Copieri de fiiere
Cteva dintre exemplele care urmeaz execut, n diverse variante i cu
diverse instrumente, copierea unui fiier n alt fiier.
2.4.2.1. Copiere ntr-o variant simpl
Acest program folosete pentru copiere o metod de tip clas (static)
numit copy. Nu efectueaz nici un control naintea copierii, lsnd pe seama
JVM s prind i s trateze eventualele excepii. Sursa este prezentat n
programului 2.4.

import java.io.*;

public class CopiereFisierS {

public static void copy(String nsursa, String ndest)
throws IOException {
// nsursa, ndest sunt numele celor doua fisiere
// fsursa, fdest sunt obiectele File asociate
// sursa, dest sunt obiectele File*Stream asociate
File fsursa = new File(nsursa);
File fdest = new File(ndest);
FileInputStream sursa = new FileInputStream(fsursa);
FileOutputStream dest = new FileOutputStream(fdest);
byte[] tampon = new byte[1024];
for ( int nr_oct=0; ; ) {
nr_oct = sursa.read(tampon);
if (nr_oct == -1)
break;
dest.write(tampon, 0, nr_oct);
} // for
sursa.close();
dest.close();
} // CopiereFisierS.copy

public static void main(String [] a) throws Exception {
copy(a[0], a[1]);
} // CopiereFisierS.main

} // CopiereFisierS
Programul 2.4. CopiereFisierS.java




74
2.4.2.2. Copiere "complicat", cu multe controale
n continuare se prezint o extindere consistent a programului de mai
sus. Programul a fost adaptat dup cel similar prezentat ntr-o lucrare de
referin: [37]. Sursa este dat n programul 2.5. Trebuie remarcat tratarea n
amnunt a tuturor situaiilor de excepie posibile.

import java.io.*;

public class CopiereFisierL {

public static void copy(String nsursa, String ndest)
throws IOException {
// nsursa, ndest sunt numele celor doua fisiere
// fsursa, fdest sunt obiectele File asociate
// sursa, dest sunt obiectele File*Stream asociate
File fsursa = new File(nsursa);
File fdest = new File(ndest);
FileInputStream sursa = null;
FileOutputStream dest = null;
byte[] tampon;
int nr_oct;
try {
// Verifica daca fisierul sursa exista si se poate citi
if (!fsursa.exists() || !fsursa.isFile())
throw new CopiereException(
"Nu exista sursa "+nsursa);
if (!fsursa.canRead())
throw new CopiereException(
"Nu se poate citi "+nsursa);
// destinatia poate exista sau nu
if (fdest.exists()) {
// daca exista, verifica daca se poate scrie
// si cere aprobarea de rescriere
if (fdest.isFile()) {
// obiectul in este stream de intrare standard
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
//DataInputStream in = new DataInputStream(System.in); in java 1.0
String raspuns;
if (!fdest.canWrite())
throw new CopiereException(
ndest+" protejat la scriere");
System.out.print(
ndest+" deja exista; il rescrieti?(Y/N): ");
System.out.flush();
raspuns = in.readLine();
if (!raspuns.equals("Y")&&!raspuns.equals("y"))
throw new CopiereException(
"Copiere abandonata");
} // if (then)
else

75
throw new CopiereException(
fdest+" nu este fisier");
} // if (else)
// directorul destinatie exista? Se poate scrie in el?
File director = daDirector(fdest);
if (!director.exists())
throw new CopiereException(
"Nu exista director parinte");
if (!director.canWrite())
throw new CopiereException(
fdest+" are directorul protejat la scriere");
// deschide cele doua streamuri
sursa = new FileInputStream(fsursa);
dest = new FileOutputStream(fdest);
tampon = new byte[1024];
// executa copierea propriu-zisa
for ( ; ; ) {
nr_oct = sursa.read(tampon);
if (nr_oct == -1)
break;
dest.write(tampon, 0, nr_oct);
} // for
}
// inchide cele doua stream-uri
finally {
if (sursa != null)
try{ sursa.close();}
catch(IOException e) {
System.out.println(e);}
if (dest != null)
try{ dest.close();}
catch(IOException e) {
System.out.println(e);}
} // finally
}

// Intoarce un obiect File asociat directorului
// destinatie al fisireului indicat de f, deoarece
// getParent() intoarce null cand fisierul f este
// specificat fara director (in directorul curent)
private static File daDirector(File f) {
String d = f.getParent();
if (d == null) {
if (f.isAbsolute())
return new File(File.separator);
else
return new File(System.getProperty("user.dir"));
} // if
return new File(d);
} // CopiereFisierL.copy

// Lansarea in executie; a[0] da numele sursei, iar a[1] al destinatiei
public static void main(String [] a) {

76
if(a.length != 2)
System.out.println(
"Utilizare: java CopiereFisier <sursa> <destinatie>");
else {
try {copy(a[0], a[1]);}
catch (IOException e) {
System.out.println(e.getMessage());
} // catch
} // if (else)
} // CopiereFisierL.main
} // CopiereFisierL

// definirea clasei pentru exceptia nou introdusa
class CopiereException extends IOException {

public CopiereException(String mesaj) {
super(mesaj);
} // CopiereException.CopiereException

} // CopiereException
Programul 2.5. CopiereFisierL.java

n acest exemplu, File este folosit pentru a verifica existena fiierelor,
dac sunt fiiere sau directori i dreptul de a fi scrise sau citite.
FileInputStream i FileOutputStream sunt folosite efectiv
pentru a face copierea fiierului surs n cel destinaie.
Obiectul in de tip BufferedReader (DataInputStream n Java
1.0), este creat din System.in pentru a fi folosit la citirea de la intrarea
standard. n exemplu, aceast citire se face cel mult o dat, pentru a se cere
aprobarea de rescriere a destinaiei existente.
Copierea se face cu ajutorul metodei statice
CopiereFisier.copy(),
lansat din metoda main().
2.4.2.3. Copiere cu un test EOF mai deosebit
Programul care urmeaz este preluat din [34]. El citete byte cu byte din
fiierul al crui nume este dat ca prim parametru n linia de comand i scrie n
fiierul al crui nume este dat prin al doilea argument al liniei de comand.
Testul de sfrit de fiier este realizat prin verificarea numrului de octei care
au mai rmas de citit. Trebuie remarcat, de asemenea, modul de construcie a
obiectului in. Sursa este prezentat n programul 2.6.



77

import java.io.*;

public class CopiereFisierEOF {

public static void main(String[] a) {
try {
String intrare = a[0], iesire = a[1];
DataInputStream in =
new DataInputStream(
new BufferedInputStream(
new FileInputStream(intrare)));
DataOutputStream out =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(iesire)));
while(in.available() != 0)
out.writeByte(in.readByte());
out.close();
in.close();
} // try
catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
} // catch
} // CopiereFisierEOF.main

} // CopiereFisierEOF
Programul 2.6. CopiereFisierEOF.java
2.4.2.4. Copiere prin schema cadru a unui program filtru
Un program filtru prelucreaz de regul o intrare standard i d un fiier
de ieire standard. Pentru utilizare, n linia de comand se vor scrie specificaiile
de redirectare a intrrii i a ieirii standard. Drept urmare, programul care
urmeaz va fi lansat folosind comanda:
java CopyTextFiltru <fisierIntrare >fisierIesire
Sursa este dat n programul 2.7.

import java.io.*;

public class CopyTextFiltru {

public static void main(String a[]) throws Exception {
String s;
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));

78
for (;;) {
s = in.readLine();
if (s==null)
break;
// Aici este locul rezervat "filtrarii"
// Noi am copiat pur si simplu
System.out.println(s);
} // for
} // CopyTextFiltru.main

} // CopyTextFiltru
Programul 2.7. CopyTextFiltru.java
2.4.2.5. Copiere prin redirectare din interior
Programul urmtor ofer un exemplu de redirectare a celor trei fiiere
standard din interiorul unui program Java. Primul argument din linia de
comand este numele noii intrri standard, al doilea este numele noii ieiri
standard iar al treilea este numele noului fiier de erori standard. Ultimele dou
nume de fiiere pot s coincid.
Comanda de lansare a programului este:
java CopyTextFiltru fisierIntrare fisierIesire fisierErori
De remarcat faptul c numele celor trei fiiere NU este precedat de < sau
>!
Sursa este prezentat n programul 2.8.

import java.io.*;

class CopyTextRedirectari {

public static void main(String[] a) {
if (a.length != 3) {
System.err.println("Apel \"CopyTextRedirectari intrare "+
"iesire erori\"");
System.exit(1);
} // if
try {
BufferedInputStream in =
new BufferedInputStream(new FileInputStream(a[0]));
PrintStream out =
new PrintStream(
new BufferedOutputStream(
new FileOutputStream(a[1])));
PrintStream err =
new PrintStream(new BufferedOutputStream(
new FileOutputStream(a[2])));

79
System.setIn(in);
System.setOut(out);
System.setErr(err);
BufferedReader brin =
new BufferedReader(
new InputStreamReader(System.in));
String s;
for (;;) {
s = brin.readLine();
if (s==null)
break;
// Aici este locul rezervat "filtrarii"
// Noi am copiat pur si simplu
System.out.println(s);
} // for
System.out.println("Terminare normala redirectare out");
System.err.println("Terminare normala redirectare err");
brin.close();
in.close();
out.close();
err.close();
} // try

catch(IOException e) {
System.err.println("Eroare IO probabil dupa redirectari");
e.printStackTrace();
} // catch

} // CopyTextRedirectari.main

} // CopyTextRedirectari
Programul 2.8. CopyTextRedirectari.java

Mai nti se definesc trei obiecte, in, out, err. Apoi, cu ajutorul
metodelor setIn, setOut i setErr din clasa System se realizeaz
redirectrile.
n sfrit, se lucreaz obinuit, similar unui filtru, cu aceste fiiere
standard: se creeaz un obiect brin pornind de la System.in, se citete linie
cu linie de la intrarea standard i se afieaz la ieirea standard.
Normal, la sfritul programului, fiierele definite prin cele trei obiecte
trebuie s fie nchise.

80
2.4.3. Conversia tipurilor primitive la tablou de bytes
2.4.3.1. Reprezentri dependente de platform
i o uniformizare a lor
n aplicaiile de comunicaii apar, relativ frecvent [10], situaii n care
procesele protagoniti ruleaz pe maini diferite. Mai mult, este posibil ca
programele n care au fost implementate procesele s fie elaborate n diferite
limbaje de programare. Aa cum se tie [13], diferitele platforme reprezint,
prin hardware, n mod diferit tipurile de date primitive. ntregii se pot repre-
zenta pe doi sau patru octei, iar ordinea octeilor poate fi bigendian sau
littleendian etc.
Cea mai fericit situaie este cnd toate programele sunt elaborate n
Java, deoarece reprezentarea datelor este independent de platform.
De foarte multe ori, aplicaiile distribuite folosesc combinaii Java - C++.
Din pcate, trebuie s se in cont de faptul c C i C++ utilizeaz reprezentrile
de pe hardware-ul pe care se lucreaz. De aici rezult o dificultate n plus:
pentru orice tip primitiv de dat transmis se impune conversia din reprezentarea
sursei n reprezentarea destinaiei.
De regul, pentru rezolvarea problemei se utilizeaz o aa-zis "repre-
zentare universal". De exemplu, la comunuicarea prin socket n C i C++ [10]
se folosesc funciile ntohs, htons, ntohl i htonl, pentru conversia
ntregilor scuri (s) i lungi (l) din/n reprezentarea local (h - host) n/din
reprezentarea universal (n - network). Tehnologia SUN-RPC [10] definete
reprezentarea universal XDR (eXternal Data Representation) i genereaz
automat xdr_funcii_de_conversie.
Pentru a veni n sprijinul programatorilor actuali, noi propunem ca
reprezentare universal reprezentarea Java. n acelai scop, prezentm n cele ce
urmeaz dou mini-biblioteci, una elaborat n Java, alta elaborat n C (C++).
Fiecare dintre ele efectueaz aciuni de conversie n/din reprezentarea Java,
folosind ca intermediar un tablou de bytes.
Tipurile primitive (notate n continuare type) de date avute n vedere
sunt: byte (Java) respectiv char (C, C++), short, int, long, float,
double.
Metodele/funciile de conversie n reprezentare Java transform repre-
zentarea local a unei date de un anumit tip, ntr-un ir de bytes care conine
reprezentarea echivalent Java a datei. Prototipurile acestei categorii de funcii,
n cele dou limbaje, sunt:

public static int addType(type source, byte[] dest,
int start)
int addType(type source, char *dest, int start)


81
Prin apelul unei astfel de funcii este convertit valoarea datei source,
de tip type, n reprezentarea echivalent Java. Octeii reprezentrii Java sunt
depui n tabloul de bytes indicat prin dest, ncepnd cu elementul de pe
poziia start. Funcia ntoarce numrul de octei depui n tabloul dest.
Metodele/funciile de conversie invers transform reprezentarea Java a
unei date dintr-un ir de bytes n reprezentarea local a datei respective.
Prototipurile acestei categorii de funcii, n cele dou limbaje, sunt:

public static int getType(byte[] source, int start,
ObjectType[] dest)
int getType(char *source, int start, type *dest)

Prin apelul unei astfel de funcii este preluat reprezentarea Java a unei
date de tip type din tabloul source ncepnd cu poziia start. Valoarea
este convertit n reprezentarea local i este depus ca prim element de tipul
respectiv n tabloul dest.

n Java, valoarea poate fi invocat prin: (type)dest[0].typeValue()
n C (C++) valoarea poate fi invocat prin (type)dest[0]
Funcia ntoarce, de asemenea, numrul de octei depui n dest.
Pentru doritorii de elemente suplimentare, cele dou implementri ofer
informaii privind lungimea i ordinea de reprezentare a diverselor tipuri de date
elementare. Implementarea Java mai ofer metoda:
public static int getLength(int t)
n acelai scop implementarea C (C++), ntr-un fel o alternativ a
funciei sizeof, ofer funcia:
int getLength(int t)
n ambele funcii argumentul t este un numr ntre 0 i 5, indicnd n
ordine tipurile byte/char, short, int, long, float, double.
n cazul Java, ntoarce unul dintre numerele 1, 2, 4, 8, 4, 8, reprezentnd
lungimile de reprezentare a celor ase tipuri de date. n cazul C/C++ ntoarce
lungimea de reprezentare pe platform a tipului de date respectiv, precum i
ordinea: bigendian sau littleendian a reprezentrii. n cazul bigendian se
ntoarce lungimea. n cazul littleendian funcia ntoarce un numr negativ,
indicnd lungimea cu semn schimbat.
n capitolele urmtoare vom folosi, n diferite contexte, o parte dintre
funciile acestei biblioteci.

82
2.4.3.2. Implementarea conversiilor n Java
Dup cum am mai artat, Java nu permite mecanism union, deci
suprapunerea peste aceeai zon de memorie a dou tipuri de date este
imposibil. n schimb, pachetul java.io ofer clasele
ByteArrayOutputStream i ByteArrayInputStream.
Obiectele de aceste tipuri sunt, de fapt, tablouri de bytes n memorie, n
care se poate scrie (prin obiecte DataOutputStream), respectiv se poate citi
(prin obiecte DataInputStream) tipuri de date primitive.
Cheia implementrii Java este constituit din metodele private
toByteArray i fromByteArray. Metoda toByteArray primete la
intrare numrul tipului de convertit t, un obiect source care "mbrac" tipul
de date primitiv ntr-un obiect de acelai tip, tabloul receptor dest i poziia
start ncepnd de unde s depun reprezentarea.
Metoda fromByteArray primete la intrare numrul tipului de
convertit t, tabloul de octei source i poziia start de unde s preia
reprezentarea i tabloul receptor dest unde s depun valoarea convertit..
Programul 2.9 prezint sursa complet a bibliotecii de conversii Java.

import java.io.*;

public class ConvertBytes {

private static final int lengthJava[] = {1, 2, 4, 8, 4, 8};

private static int toByteArray(int t, Object source,
byte[] dest, int start) {
if ((source==null)||(dest==null)||
(start<0)||(dest.length<start+lengthJava[t]))
return 0;
byte b[];
ByteArrayOutputStream ob = new ByteArrayOutputStream();
DataOutputStream o = new DataOutputStream(ob);
try {
switch (t) {
case 0: o.writeByte(((Byte)source).byteValue());
break;
case 1: o.writeShort(((Short)source).shortValue());
break;
case 2: o.writeInt(((Integer)source).intValue());
break;
case 3: o.writeLong(((Long)source).longValue());
break;
case 4: o.writeFloat(((Float)source).floatValue());
break;
case 5: o.writeDouble(((Double)source).doubleValue());

83
break;
} // switch
} // try
catch (IOException e) {
e.printStackTrace();
} // catch
b = ob.toByteArray();
System.arraycopy(b, 0, dest, start, lengthJava[t]);
return lengthJava[t];
} // ConvertBytes.toByteArray

private static int fromByteArray(int t, byte[] source,
int start, Object[] dest) {
if ((source==null)||(dest==null)||(start<0)||
(source.length<start+lengthJava[t])||(dest.length<1))
return 0;
ByteArrayInputStream ib =
new ByteArrayInputStream(source, start, lengthJava[t]);
DataInputStream i = new DataInputStream(ib);
Object ob = null;
try {
switch (t) {
case 0: ob = new Byte(i.readByte()); break;
case 1: ob = new Short(i.readShort()); break;
case 2: ob = new Integer(i.readInt()); break;
case 3: ob = new Long(i.readLong()); break;
case 4: ob = new Float(i.readFloat()); break;
case 5: ob = new Double(i.readDouble()); break;
} // switch
} // try
catch (IOException e) {
e.printStackTrace();
} // catch
dest[0] = ob;
return lengthJava[t];
} // ConvertBytes.fromByteArray

public static int addByte(byte source, byte[] dest, int start) {
return toByteArray(0, new Byte(source), dest, start);
} // ConvertBytes.addByte

public static int addShort(short source, byte[] dest, int start)
{
return toByteArray(1, new Short(source), dest, start);
} // ConvertBytes.addShort

public static int addInt(int source, byte[] dest, int start) {
return toByteArray(2, new Integer(source), dest, start);
} // ConvertBytes.addInt

public static int addLong(long source, byte[] dest, int start) {
return toByteArray(3, new Long(source), dest, start);
} // ConvertBytes.addLong

84

public static int addFloat(float source, byte[] dest, int start)
{
return toByteArray(4, new Float(source), dest, start);
} // ConvertBytes.addFloat

public static int addDouble(double source, byte[] dest,
int start) {
return toByteArray(5, new Double(source), dest, start);
} // ConvertBytes.addFloat

public static int getByte(byte[] source, int start, Byte[] dest)
{
return fromByteArray(0, source, start, dest);
} // ConvertBytes.getByte

public static int getShort(byte[] source, int start,
Short[] dest) {
return fromByteArray(1, source, start, dest);
} // ConvertBytes.getShort

public static int getInt(byte[] source, int start,
Integer[] dest) {
return fromByteArray(2, source, start, dest);
} // ConvertBytes.getInt

public static int getLong(byte[] source, int start, Long[] dest)
{
return fromByteArray(3, source, start, dest);
} // ConvertBytes.getLong

public static int getFloat(byte[] source, int start,
Float[] dest) {
return fromByteArray(4, source, start, dest);
} // ConvertBytes.getFloat

public static int getDouble(byte[] source, int start,
Double[] dest) {
return fromByteArray(5, source, start, dest);
} // ConvertBytes.getDouble

public static int getLength(int t) {
if ((t<0)||(t>5))
return 0;
return lengthJava[t];
} // ConvertBytes.getLength

} // ConvertBytes
Programul 2.9. ConvertBytes.java


85
Credem c este util s oferim, spre comparaie, alternative de realizare a
conversiilor. De exemplu, dac se dorete n Java conversia unui ir de 4 bytes
n ordinea bigendian ntr-un int, atunci s-ar putea folosi una din urmtoarele
dou soluii:

Soluia 1-a: Fie in un obiect de tip ByteArrayInputStream construit
cu tabloul de 4 bytes de convertit i i ntregul de tip int unde va
fi depus rezultatul conversiei. Secvena urmtoare - schema lui
Horner - realizeaz conversia:

i = (((int)in.read()*256 +
(int)in.read())*256 +
(int)in.read())*256 +
(int)in.read();

Soluia 2-a: S presupunem c in este un obiect de tip DataInputStream,
deschis pentru canalul pe care urmeaz s fie citii cei 4 bytes, n
ordinea bigendian, care urmeaz a fi convertii, iar i ntregul de
tip int ce conine rezultatul conversiei. Conversia este realizat
tot prin schema lui Horner, astfel:

i = (((int)in.readUnsignedByte()*256 +
(int)in.readUnsignedByte())*256 +
(int)in.readUnsignedByte())*256 +
(int)in.readUnsignedByte();

Pentru operaia invers, n ipoteza c ntregul I este un numr pozitiv iar
b tabloul de bytes care va conine conversia, secvena este similar cu
urmtoarea:

for (k=3; k>=0; k--) {
b[k] = i % 256;
i /= 256
}

Lsm cititorul s aleag soluia pe care o consider mai convenabil.
2.4.3.3. Implementarea conversiilor n C
Implementarea C definete mai nti lungimile de reprezentare Java i
cele C dependente de platform. Lungimile concrete sunt obinute prin funcii
sizeof. Faptul c ordinea de reprezentare este bigendian sau littleendian se
decide la primul apel al primei funcii. La fiecare apel se apeleaz funcia
getLength. Pe baza variabilei first se decide dac este primul apel sau
unul dintre urmtoarele. n cazul primului apel, printr-o suprapunere a unui

86
ntreg cu un caracter se decide dac este ordinea bigendian sau littleendian.
Dac este cazul, se schimb semnul lungimilor platformei.
Cheia conversiilor const n dou funcii: C2Java i Java2C. Ambele
primesc la intrare tipul t al tipului de convertit i doi pointeri, source i
dest. Ambele convertesc, ori din C n Java, ori din Java n C. Dac este vorba
de littleendian, reprezentarea inverseaz ordinea octeilor. Aceste dou funcii
trunchiaz dac reprezentarea sursei este prea lung, respectiv adaug zerouri
sau bitul de semn n locul cuvenit, atunci cnd reprezentarea destinaie este mai
lung.
Programul 2.10 prezint sursa C a acestei biblioteci.


#include <stdio.h>
#include <string.h>

static int lengthJava[] = {1,2,4,8,4,8};
static int lengthC[] = {sizeof(char),sizeof(short),sizeof(int),
sizeof(long),sizeof(float),sizeof(double)};
static int first=1;

int getLength(int t) {
// Intoarce 0 la eroare de apel
// >0 lungime reprezentare bigendian
// <0 -lungime reprezentare littleendian
if ((t<0)||(t>5))
return 0;
if (first) {
int i;
union {
char c;
int i;
} x;
first = 0;
x.i = 1;
if (x.c == 1)
for (i=1; i<6; i++)
lengthC[i] = -lengthC[i];
} // if
return lengthC[t];
} // ConvertBytes.lengthOrd

int C2Java(int t, char *source, char *dest) {
// Intoarce 0 la eroare de apel
// >0 lungimea transferata in dest
int i, j, k;
char c, copy[32];
k = getLength(t);
if ((k==0)||(source==NULL)||(dest==NULL))
return 0;
if (t==0) {

87
dest[0] = source[0];
return 1;
} // if
if (k<0) {
k = -k;
for (i=0, j=k-1; i<k; i++,j--)
copy[i] = source[j];
}
else
memcpy(copy, source, k);
if (k==lengthJava[t])
memcpy(dest, copy, k);
if (k>lengthJava[t]) {
if (t>3)
memcpy(dest, copy, lengthJava[t]);
else
memcpy(dest, copy+k-lengthJava[t], lengthJava[t]);
} // if
if (k<lengthJava[t]) {
c = 0;
if ((t<4)&&(copy[0]<0))
c = 0xff;
memset(dest, c, lengthJava[t]);
if (t>3)
memcpy(dest, copy, lengthJava[t]);
else
memcpy(dest+lengthJava[t]-k, copy, lengthJava[t]);
} // if
return lengthJava[t];
} // ConvertBytes.C2Java

int Java2C(int t, char *source, char *dest) {
// Intoarce 0 la eroare de apel
// >0 lungimea transferata in dest
int i, j, k, x;
char c, copy[32];
k = getLength(t);

if ((k==0)||(source==NULL)||(dest==NULL))
return 0;
if (t==0) {
dest[0] = source[0];
return 1;
} // if
x = 1;
if (k<0) {
x = -1;
k = -k;
} // if
if (k==lengthJava[t])
memcpy(copy, source, k);
if (k<lengthJava[t]) {
if (t>3)

88
memcpy(copy, source, k);
else
memcpy(copy, source+lengthJava[t]-k, k);
} // if
if (k>lengthJava[t]) {
c = 0;
if ((t<4)&&(source[0]<0))
c = 0xff;
memset(copy, c, k);
if (t>3)
memcpy(copy, source, lengthJava[t]);
else
memcpy(copy, source+k-lengthJava[t], lengthJava[t]);
} // if


if (x>0)
memcpy(dest, copy, k);
else
for (i=0, j=k-1; i<k; i++,j--)
dest[i] = copy[j];
return k;
} // ConvertBytes.Java2C

int addByte(char source, char *dest, int start) {
return C2Java(0, (char *)&source, dest+start);
} // ConvertBytes.addByte

int addShort(short source, char *dest, int start) {
return C2Java(1, (char *)&source, dest+start);
} // ConvertBytes.addShort

int addInt(int source, char *dest, int start) {
return C2Java(2, (char *)&source, dest+start);
} // ConvertBytes.addInt

int addLong(long source, char *dest, int start) {
return C2Java(3, (char *)&source, dest+start);
} // ConvertBytes.addLong

int addFloat(float source, char *dest, int start) {
return C2Java(4, (char *)&source, dest+start);
} // ConvertBytes.addFloat

int addDouble(double source, char *dest, int start) {
return C2Java(5, (char *)&source, dest+start);
} // ConvertBytes.addDouble

int getByte(char *source, int start, char *dest) {
return Java2C(0, source+start, (char *)dest);
} // ConvertBytes.getByte

int getShort(char *source, int start, short *dest) {

89
return Java2C(1, source+start, (char *)dest);
} // ConvertBytes.getShort

int getInt(char *source, int start, int *dest) {
return Java2C(2, source+start, (char *)dest);
} // ConvertBytes.getInt

int getLong(char *source, int start, long *dest) {
return Java2C(3, source+start, (char *)dest);
} // ConvertBytes.getLong

int getFloat(char *source, int start, float *dest) {
return Java2C(4, source+start, (char *)dest);
} // ConvertBytes.getFloat

int getDouble(char *source, int start, double *dest) {
return Java2C(5, source+start, (char *)dest);
} // ConvertBytes.getDouble
Programul 2.10. ConvertBytes.cpp

Lsm pe seama cititorului s descopere detaliile mecanismelor de
conversie. Pentru prezentarea standardelor de reprezentare a acestor tipuri
primitive, se poate consulta lucrarea [13].
i aici credem c este util s oferim, spre comparaie, alternative de
realizare a conversiilor. De exemplu, dac se dorete trimiterea unui ntreg i
din C ntr-un ir b de 4 bytes spre Java, se poate face apel la funcia htonl din
pachetul socket [10]:

l = htonl((long)i);
if (sizeof(long)==4)
memcpy(b, &l, 4);
else
memcpy(b, &l+4, 4);
Dac se dorete conversia ntr-un int n C din 4 bytes sosii din Java n
tabloul b, atunci conversia se poate face folosind funcia pereche ntohl din
socket [10]:
l=0;
if (sizeof(long)==4)
memcpy(&l, b, 4);
else
memcpy(&l+4, b, 4);
l = (int)ntohl(l);
Lsm la altitudinea cititorului s aleag soluia pe care o consider mai
convenabil.

90
2.4.4. Alte exemple de I/O
2.4.4.1. Simularea unui vector mare
Acest exemplu permite utilizarea unui tablou de dimensiuni foarte mari,
ca i cnd ar fi n memoria intern, ns el este extins pe disc. Pentru schimbul
cu discul se folosesc metode ale clasei RandomAccessFile. Textul surs
este prezentat n programul 2.11.

import java.io.*;

public class VectorMare {
long n;
String FISIER = "Vector";
RandomAccessFile f;

public VectorMare(long n) {
try {
this.n = n;
FileOutputStream f = new FileOutputStream(FISIER);
for (int i=0; i<8*n;i++)
f.write(0);
f.close();
this.f = new RandomAccessFile(FISIER, "rw");
} // try
catch (IOException e) {
} // catch
} // VectorMare.VectorMare

public double get(long i) {
double x = 0.0;
try{
f.seek(8*i);
x = f.readDouble();
} // try
catch(Exception e){
} // catch
return(x);
} // VectorMare.get

public void put(long i, double d) {
try {
f.seek(8*i);
f.writeDouble(d);
} // try
catch (Exception e) {
} // catch
} // VectorMare.put

public static void main(String a[]) {

91
VectorMare v = new VectorMare(10000);
v.put(45,45.0);
v.put(38,38.0);
v.put(22,22.0);
v.put(99,99.0);
System.out.println(v.get(40));
System.out.println(v.get(99));
System.out.println(v.get(38));
} // VectorMare.main

} // VectorMare
Programul 2.11. VectorMare.java

Construcia vectorului nseamn completarea cu zerouri a ntregului
spaiu disc (fiierul Vector) n care va fi gzduit tabloul. Se definesc apoi
metodele put i get de acces la vector, iar n metoda main se depun sau se
citesc cteva numere.
2.4.4.2. Comprimarea (Zip) a fiierelor
Programul care urmeaz exemplific cteva aciuni n legtur cu com-
primarea fiierelor. Nu intenionm s detaliem acest gen de activiti, utiliza-
torul poate singur s se documenteze din manualele electronice i help-urile
existente. O s prezentm, telegrafic, scopul fiecreia dintre clasele care apar n
program.

Adler32
Calculeaz o sum de control de tip Adler32 pentru un stream
de date.
CheckedInputStream i CheckedOutputStream
Definesc cte un stream de intrare, respectiv de ieire, n care
ntreine i cte o sum de control de un anumit tip.
ZipInputStream i ZipOutputStream
Definete stream de intrare/de ieire din/n fiier de tip zip. Inclu-
de n definiie i metodele de compresie/decompresie aferente.
ZipFile
Este analogul clasei File i definete ntr-un director un fiier de
tip zip.
ZipEntry

92
Definete o intrare pentru un fiier introdus/existent ntr-o arhiv
zip.
Sursa este prezentat n programul 2.12.

// Comprimarea unui numar de fisiere, ale caror nume sunt date in
// linia de comanda, intr-un fisier Zip folosind metodele oferite
// in acest sens de catre pachetul java.util.zip

import java.io.*;
import java.util.*;
import java.util.zip.*;

public class ZipCompress {

public static void main(String[] a) {
String fisierZip = "test.zip";
try {
FileOutputStream f =
new FileOutputStream(fisierZip);
CheckedOutputStream csum =
new CheckedOutputStream(f, new Adler32());
ZipOutputStream out = new ZipOutputStream(
new BufferedOutputStream(csum));
out.setComment("Test Java Zipping");
// Comentariul de deasupra se poate citi (numai) in proprietatile fisierului test.zip!
for(int i = 0; i < a.length; i++) {
System.out.println("Arhiveaza fisierul " + a[i]);
BufferedReader in =
new BufferedReader(new FileReader(a[i]));
out.putNextEntry(new ZipEntry(a[i]));
int c;
while((c = in.read()) != -1)
out.write(c);
in.close();
} // for
out.close();
// Checksum este valid numai dupa inchiderea fisierului
System.out.println("Checksum: " +
csum.getChecksum().getValue());
// Se extrag fisierele:
System.out.println("");
FileInputStream fi = new FileInputStream(fisierZip);
CheckedInputStream csumi = new CheckedInputStream(
fi, new Adler32());
ZipInputStream in2 = new ZipInputStream(
new BufferedInputStream(csumi));
ZipEntry ze;
System.out.println("Checksum: " +
csumi.getChecksum().getValue());
while((ze = in2.getNextEntry()) != null) {
System.out.println("Reading file " + ze);
int x;

93
while((x = in2.read()) != -1)
System.out.write(x);
} // while
in2.close();
// Mod alternativ de deschidere si citire
ZipFile zf = new ZipFile(fisierZip);
Enumeration e = zf.entries();
while(e.hasMoreElements()) {
ZipEntry ze2 = (ZipEntry)e.nextElement();
System.out.println("File: " + ze2);
// ... si se extrag fisierele ca si inainte
} // while
} // try
catch(Exception e) {
e.printStackTrace();
} // catch
} // ZipCompress.main

} // ZipCompress
Programul 2.12. ZipCompress.java

n prima etap sunt create obiectele f fiierul zip, csum suma de
control i out care permite comprimarea fiierelor n arhiva test.zip. Dup
introducerea unui comentariu n arhiv, sunt introduse
(out.nextPutEntry) fiierele comprimate ale cror nume sunt date n linia
de comand.
Apoi se extrag, n dou moduri, fiierele din arhiv.
2.4.4.3. Serializarea i pstrarea persistenei obiectelor Java
Serializarea este un mecanism prin care un obiect din memorie este
transformat ntr-un ir de octei, ir care poate fi depus ntr-un fiier. Ulterior
irul corespunztor obiectului poate fi extras din fiier i prin acesta obiectul
este reconstituit. Reconstituirea unui obiect din forma serializat se poate face
mai trziu fie pe aceeai main, fie pe o alt platform dect cea de pe care s-a
creat serializarea.
Operaia de serializare este recursiv, n sensul c dac un obiect este
serializat atunci toate obiectele componente ale lui sunt serializate.
Pentru a fi serializabil, un obiect trebuie s implementeze interfaa
java.io.Serializable. Aceast interfa nu conine nici o metod, deci nu este
nevoie s implementm nimic pentru ea; este pur i simplu o specificare
implements. Marea majoritate a claselor standard din Java sunt serializa-
bile.

94
O clas serializabil trebuie s aib un constructor public fr parametri
i s nu conin n ea obiecte neserializabile. JVM determin complet calitatea
unui obiect de a fi sau nu serializabil doar n timpul execuiei. De exemplu,
obiectele cu atribut transient, ca i cele implementate nativ, nu sunt
serializabile!
Pentru salvarea i refacerea obiectelor prin serializare se folosesc clasele
ObjectInputStream i ObjectOutputStream, iar ca i metode
readObject i writeObject.
n cele ce urmeaz schim un exemplu de asigurare a persistenei unui
grup de obiecte folosind serializarea. Exemplul este o interfa grafic care
actualizeaz ntr-o sesiune de lucru diverse proprieti ale unor obiecte. Pentru
ca ntr-o sesiune ulterioar obiectele s conin modificrile sesiunii precedente,
programul trebuie s citeasc obiectele din fiier la nceputul sesiunii i s le
salveze n acelai fiier la sfritul sesiunii.
n cazul nostru este vorba de apte obiecte: nume, coduri,
setPointer, machete, codE1, lungime, valoare, avnd unul
dintre tipurile Vector, String, Integer, Double. Pentru pstrarea
obiectelor serializate se folosete fiierul SalvatorObiecte. Schema dup
care se asigur persistena este prezentat mai jos:

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

class MakeSemantics extends Frame implements ActionListener {

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

String nume, machete;
Vector coduri, setPointer;
Integer codEl, lungime;
Double valoare;

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

public static void main(String a[]) throws Exception {
MakeSemantics ms = new MakeSemantics();
ms. show();
ms. init();
} // MakeSemantics.main()

public void init() throws Exception {

// Actiuni desfasurate la inceputul executiei programului

ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("temp"));

95
nume = (String)ois.readObject();
coduri = (Vector)ois.readObject();
setPointer = (Vector)ois.readObject();
machete = (String)ois.readObject();
codEl = (Integer)ois.readObject();
lungime = (Integer)ois.readObject();
valoare = (Double)ois.readObject();
ois.close();

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

} // MakeSemantics.init

public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("pred"))

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
else if (command.equals("saveExit")) {

// Actiuni desfasurate inainte de terminarea sesiunii

try {
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("temp"));
oos.writeObject(nume);
oos.writeObject(coduri);
oos.writeObject(setPointer);
oos.writeObject(machete);
oos.writeObject(codEl);
oos.writeObject(lungime);
oos.writeObject(valoare);
oos.close();
} // try
catch (Exception x) {
} // catch
System.exit(0);
} // if
} // MakeSemantics.actionPerformed

} // MakeSemantics

De remarcat c valorile numerice au fost reprezentate ca i obiecte, nu ca
i date primitive. De asemenea trebuie remarcat faptul c ordinea de scriere a
obiectelor, i tipul acestora coincide cu cea de la citire.
nainte de prima sesiune de lucru trebuie creat un fiier vid cu numele
SalvatorObiecte, drept urmare iniial toate obiectele vor fi vide.

96
2.4.4.4. Gruparea fiierelor listabile
Programul parcurge recursiv substructura de directori cu rdcina n
directorul curent i reine ntr-un fiier text toate fiierele avnd anumite tipuri.
Pentru a nu pierde informaii, utilizatorul trebuie s aib grij ca n directorul
curent s nu existe fiiere cu numele: DeListat i text. Programul creeaz
aceste dou fiiere i l pstreaz pe primul dintre ele.
Fiierul DeListat conine la nceput un fel de cuprins care repereaz
fiierele la nivel de numr de linie, sub forma:

9 linii incepand cu 0 in:
D:\FLORIN\CARTI\Java\.\AgendaJAR\Agenda.txt
139 linii incepand cu 9 in:
D:\FLORIN\CARTI\Java\.\AgendaJAR\AgendaAp.javan
226 linii incepand cu 148 in:
D:\FLORIN\CARTI\Java\.\AgendaJAR\AgendaFull.java
4 linii incepand cu 374 in:
D:\FLORIN\CARTI\Java\.\AgendaJAR\Ap0.txt
6 linii incepand cu 378 in:
D:\FLORIN\CARTI\Java\.\AgendaJAR\Ap1.txt
4 linii incepand cu 384 in:
D:\FLORIN\CARTI\Java\.\AgendaJAR\Ap2.txt
2 linii incepand cu 388 in:
D:\FLORIN\CARTI\Java\.\AgendaJAR\Ap3.txt
110 linii incepand cu 390 in:
D:\FLORIN\CARTI\Java\.\AgendaJAR\Ap4.txt
142 linii incepand cu 500 in:
D:\FLORIN\CARTI\Java\.\AgendaJAR\Campuri.java
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Urmeaz apoi, unul dup altul, fiierele, fiecare precedat de cte un
antet, sub forma:

!!! Urmeaza textele sursa

Total 0 linii sursa pana aici
############################################
# D:\FLORIN\CARTI\Java\.\AgendaJAR\Agenda.txt
############################################
Name OfficePhone HomePhone Fax Email HomePage Address
_ _ _ _ _ _ _
_Pagina vida _ _ _ _ _ _
Academie 192363 _ _ _ _ _
Acr 927 _ _ _ _ _
Administrativ 257 _ _ _ _ _
Aeroport 416702 416016 (bagaje pierdute) _ _ _ _
AGNOR 094 568910 01 3405457 _ 01 3405456 office@agnor.ro
www.agnor.ro _
Ziua 194891 194224 _ _ _ _ Redactia ziarului
Publicitate 432501 2

Total 9 linii sursa pana aici

97
############################################
# D:\FLORIN\CARTI\Java\.\AgendaJAR\AgendaAp.javan
############################################
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public class AgendaAp extends Applet
implements ActionListener, KeyListener {
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Total 378 linii sursa pana aici
############################################
# D:\FLORIN\CARTI\Java\.\AgendaJAR\Ap1.txt
############################################
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public class AgendaAp extends Applet
implements ActionListener, KeyListener {
Total 384 linii sursa pana aici
############################################
# D:\FLORIN\CARTI\Java\.\AgendaJAR\Ap2.txt
############################################
static int i;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Total 500 linii sursa pana aici
############################################
# D:\FLORIN\CARTI\Java\.\AgendaJAR\Campuri.java
############################################
import java.io.*;
import java.util.*;
public class Campuri {
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Aceast form de reunire a fiierelor de anumite tipuri permite o grupare
i o consultare relativ comod a fiierelor citibile dintr-o substructur. De
asemenea, n urma listrii se pot ndosaria i consulta n forma tiprit.
Textul surs este dat n programul 2.13. Lsm pe seama cititorului s
citeasc i s neleag modul de lucru al programului.

// Grupeaza intr-un singur fisier text numit "DeListat", sub forma tiparibila,
// toate fisierele de anumite tipuri (indicate prin tabloul "tipuri")
// din directorul curent si din toate subdirectoarele lui.
// Fisierul "DeListat" incepe cu un cuprins care indica numere de linii
// Fiecare fisier inglobat incepe cu un antet in care se scrie:
// linia de inceput din grup si cate linii are el
import java.io.*;

public class ListariSurse {
final String[] tipuri = {".java",".html",".txt",".xml",
".bat",".sh",".awt"};

98
PrintStream cuprins, text;
BufferedReader ft;
long total;
ListariSurse() {
try {
cuprins = new PrintStream(
new FileOutputStream("DeListat"));
text = new PrintStream(new FileOutputStream("text"));
total = 0;
} // try
catch (Exception e) {
e.printStackTrace();
} // catch
} // ListariSurse

public void unFile(String nf) throws Exception {
int i, p;
String nume;
String[] list;
File f = new File(nf);
if (f.isDirectory()) {
list = f.list();
for (i=0; i<list.length; i++)
unFile(nf+File.separator+list[i]); // recursiv in director interior
} // if
nume = f.getName();
for (i=0; i<tipuri.length; i++) {
p = nume.lastIndexOf(tipuri[i]);
if (p < 0 )
continue;
p = 0;
ft = new BufferedReader(new InputStreamReader(
new FileInputStream(f.getPath())));
text.println("Total "+total+" linii sursa pana aici");
text.println("############################################");
text.println("# "+f.getAbsolutePath());
text.println("############################################");
for (;;) {
nume = ft.readLine();
if (nume == null)
break;
nume = "."+nume;
nume = nume.trim();
nume = nume.substring(1);
if (nume.length() == 0)
continue;
p++;
text.println(nume);
} // for: citiri dintr-un fisier
text.println();
ft.close();
cuprins.println(p+" linii incepand cu "+total+
" in: "+f.getAbsolutePath());

99
total += p;
return;
} // for: alt fisier de acelasi tip
return;
} // ListariSurse.unFile

public void deListat() throws Exception{
String s;
File f;
cuprins.println();
cuprins.println("!!! Urmeaza textele sursa");
cuprins.println();
text.close();
ft = new BufferedReader(new InputStreamReader(
new FileInputStream("text")));
for (;;) {
s = ft.readLine();
if (s==null)
break;
cuprins.println(s);
} // for
ft.close();
cuprins.close();
f = new File("text");
f.delete();
} // ListariSurse.deListat


public static void main(String[] a) throws Exception {
ListariSurse ls = new ListariSurse();
ls.unFile(".");
ls.deListat();
} // ListariSurse.main

} // ListariSurse
Programul 2.13. ListariSurse.java
2.4.4.5. Afiare ASCII i hexazecimal
Programul urmtor este inspirat din comanda od de sub Unix. El
afieaz coninutul fiierului att n ASCII, ct i fiecare octet n hezazecimal.
Programul presupune c fiierul de afiat este intrarea lui standard. Sursa
od.java este dat n programul 2.14.

import java.io.*;

public class od {

public static void main(String a[]) throws Exception {

100
int i, k=8, j, adresa = 0;
String f = " \\n \\r \\t";
byte[] b = {'\n','\r','\t'};
String c = new String(b);
String h = "0123456789ABCDEF";
String spatii = " ";
StringBuffer liniea = new StringBuffer(spatii);
StringBuffer liniec = new StringBuffer(spatii);
for (;;) {
if ((adresa %16) == 0) {
System.out.println(liniea);
System.out.println(liniec);
liniea = new StringBuffer(" ");
liniec = new StringBuffer(new String(liniea));
for (i = adresa, k=5; k>=0; k--) {
liniea.setCharAt(k, h.charAt(i % 16));
i /= 16;
} // for
k = 8;
} // if
i = System.in.read();
if (i < 0)
break;
if ((i >= ' ')&&(i<128))
liniea.setCharAt(k, (char)i);
else if ((j=c.indexOf((char)i))>= 0)
liniea.replace(k-2, k+1, f.substring(3*j, 3+3*j));
liniec.setCharAt(k, h.charAt(i%16));
liniec.setCharAt(k-1, h.charAt(i/16));
k += 3;
adresa++;
} // for
System.out.println(liniea);
System.out.println(liniec);
System.out.println();
} // od.main

} // od
Programul 2.14. od.java

Dac se lanseaz comanda:
java od <RezumatDirector.java
unde intrarea standard este unul dintre fiierele surs prezentat ntr-o seciune
precedent, atunci rezultatul afirii este:
000000 i m p o r t j a v a . i o . *
69 6D 70 6F 72 74 20 6A 61 76 61 2E 69 6F 2E 2A
000010 ; \r \n p u b l i c c l a s s
3B 0D 0A 70 75 62 6C 69 63 20 63 6C 61 73 73 20
000020 R e z u m a t D i r e c t o r

101
52 65 7A 75 6D 61 74 44 69 72 65 63 74 6F 72 20
000030 { \r \n p u b l i c s t a
7B 0D 0A 20 20 20 70 75 62 6C 69 63 20 73 74 61
000040 t i c v o i d m a i n ( S t
74 69 63 20 76 6F 69 64 20 6D 61 69 6E 28 53 74
000050 r i n g [ ] a ) { \r \n
72 69 6E 67 5B 5D 20 61 29 20 7B 0D 0A 20 20 20
000060 t r y { \r \n
20 20 20 74 72 79 20 7B 0D 0A 20 20 20 20 20 20
000070 F i l e p a t h = n
20 20 20 46 69 6C 65 20 70 61 74 68 20 3D 20 6E
000080 e w F i l e ( ( a . l e n g t
65 77 20 46 69 6C 65 28 28 61 2E 6C 65 6E 67 74
000090 h = = 0 ) ? " . " : a [ 0 ] ) ;
68 3D 3D 30 29 3F 22 2E 22 3A 61 5B 30 5D 29 3B
0000A0 \r \n S t r i n
0D 0A 20 20 20 20 20 20 20 20 20 53 74 72 69 6E
0000B0 g [ ] l i s t = p a t h .
67 5B 5D 20 6C 69 73 74 20 3D 20 70 61 74 68 2E
0000C0 l i s t ( ) ; \r \n
6C 69 73 74 28 29 3B 0D 0A 20 20 20 20 20 20 20
0000D0 f o r ( i n t i = 0 ;
20 20 66 6F 72 28 69 6E 74 20 69 20 3D 20 30 3B
0000E0 i < l i s t . l e n g t h
20 69 20 3C 20 6C 69 73 74 2E 6C 65 6E 67 74 68
0000F0 ; i + + ) \r \n
3B 20 69 2B 2B 29 0D 0A 20 20 20 20 20 20 20 20
000100 S y s t e m . o u t . p
20 20 20 20 53 79 73 74 65 6D 2E 6F 75 74 2E 70
000110 r i n t l n ( l i s t [ i ] ) ;
72 69 6E 74 6C 6E 28 6C 69 73 74 5B 69 5D 29 3B
000120 \r \n } / / t r y \r \n
0D 0A 20 20 20 20 20 20 7D 2F 2F 74 72 79 0D 0A
000130 c a t c h ( E x c e
20 20 20 20 20 20 63 61 74 63 68 28 45 78 63 65
000140 p t i o n e ) { \r \n
70 74 69 6F 6E 20 65 29 20 7B 0D 0A 20 20 20 20
000150 e . p r i n t S t a c
20 20 20 20 20 65 2E 70 72 69 6E 74 53 74 61 63
000160 k T r a c e ( ) ; \r \n
6B 54 72 61 63 65 28 29 3B 0D 0A 20 20 20 20 20
000170 } / / c a t c h \r \n } /
20 7D 2F 2F 63 61 74 63 68 0D 0A 20 20 20 7D 2F
000180 / R e z u m a t D i r e c t o r
2F 52 65 7A 75 6D 61 74 44 69 72 65 63 74 6F 72
000190 . m a i n \r \n } / / R e z u m
2E 6D 61 69 6E 0D 0A 7D 20 2F 2F 52 65 7A 75 6D
0001A0 a t D i r e c t o r
61 74 44 69 72 65 63 74 6F 72

102
2.4.4.6. Blocarea accesului la (o poriune dintr-)un fiier
ncepnd cu Java 1.4, pe lng pachetul java.io a mai aprut pachetul
java.nio i alte pachete nrudite cu acesta. Printre altele, prin intermediul
acestora s-au introdus concepte noi, printre care acela de channel(canal).
Un canal reprezint o conexiune ataat la o entitate cum ar fi: un
periferic, un fiier, un socket, o component program etc. Aceste entiti trebuie
s fie capabile s execute una sau mai multe operaii I/O cum ar fi citire sau
scriere. Canalele sunt folosite n principal pentru a se asigura accese multithread
sigure.
Clasa FileChannel ofer faciliti de citire, scriere i manipulare
fiiere. Pe lng operaiile uzuale de citire i de scriere, prin FileChannel se
pot efectua o serie de operaiimai speciale, printre care amintim:
Octeii pot fi citii/scrii n poziii absolute n fiier, fr ca prin
aceasta s fie afectat poziia curent din fiier.
O poriune din fiier poate fi mapat n memoria intern, ceea ce
pentru fiierele mari conduce la prelucrri mai eficiente.
Un fiier ntreg, sau numai o poriune contigu din el poate fi blocat
exclusiv de un thread/program; toi ceilali protagoniti care doresc s
acceseze poriunea respectiv rmnnd n ateptare pn la deblo-
carea de ctre protagonistul care a blocat.
Programul 2.15 exemplific, ntr-o manier simpl, blocarea unui fiier.
Pentru blocare se poate folosi fie metoda lock() de blocare a ntregului fiier,
fie metoda lock(long start, long lungime, boolean
partajabil), pentru blocarea unei poriuni.
Numele fiierului care se blocheaz este dat n linia de comand. Am
indicat blocarea unei poriuni, care aici coincide cu ntreg fiierul. Pentru fiecare
eveniment este afiat momentul apariiei lui.

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;

public class BlocareFisier {

public static void main(String a[]) throws Exception {
String fisier = a[0];
RandomAccessFile r = new RandomAccessFile(fisier, "rw");
FileChannel c = r.getChannel();
System.out.println("Asteapta blocare \""+fisier+"\" "+
new Date());
FileLock l = c.lock(0,r.length(),false);
System.out.println("\""+fisier+"\" blocat "+

103
new Date());
System.out.println("Dati ENTER pentru eliberare:");
System.in.read(new byte[10]);
l.release();
System.out.println("\""+fisier+"\" eliberat "+
new Date());
} // BlocareFisier.main

} // BlocareFisier
Programul 2.15. BlocareFisier.java

Presupunem c n dou ferestre lansm dou instane ale acestui
program. Mai nti, la nici una nu rspundem cu ENTER. Cele dou ferestre vor
arta ca n fig. 2.1 i 2.2.


Figura 2.1. Prima lansare BlocareFisier


Figura 2.2. A doua lansare BlocareFisier

Dup ce n prima fereastr se tasteaz ENTER, cele dou ferestre vor
arta ca n fig. 2.3 i 2.4.


Figura2.3. Prima fereastr, dup <ENTER>

104


Figura 2.4. A doua fereastr, dup <ENTER>
2.4.4.7. Fragmentarea i reunirea fiierelor foarte mari
n multe situaii, se pune problema transportului unui fiier foarte mare
de pe un suport pe altul, sau de pe un calculator pe altul. n general, sistemele
de operare dispun de utilitare/comenzi care s sprijine aceste activiti. Noi
propunem o pereche de astfel de programe, extrem de simple i universale.
Simplitatea lor deriv din faptul c orice acces la fiiere se face pentru un singur
octet, att pentru citiri ct i pentru scrieri. Evident, o astfel de soluie nu este
prea eficient i lsm pe seama cititorului s rescrie aceste programe aa nct
s scrie i s citeasc la fiecare acces un numr mare de octei.
Programul de fragmentare, Split, primete n linia de comand numele
fiierului mare care trebuie s fie fragmentat. De asemenea, un eventual al
doilea parametru precizeaz care este dimensiunea, n octei, a unei buci de
fiier. n caz c acest parametru lipsete, programul fixeaz o dimensiune
implicit a bucilor.
Programul pretinde ca fiierul mare s fie n directorul curent. Bucile
pe care le creeaz sunt fiiere de lungime egal cu lungimea fixat a bucii, cu
excepia ultimului fiier (ultimei buci) care are dimensiunea mai mic sau
egal ca dimensiunea bucii. Aceste fiiere sunt create tot n directorul curent,
numele lor fiind, n ordine, numerele ntregi de cinci cifre: "00001",
"00002", . . .
La fiecare trecere la o nou bucat de fiier programul afieaz un mesaj
de informare prin care se arat ci octei au mai rmas de depus n buci. Sursa
este prezentat n programul 2.16.

import java.io.*;

public class Split {

public static void main(String a[]) throws Exception {
DataInputStream in;
DataOutputStream out = null;
long BUCATA =
(a.length >= 2)? (Long.parseLong(a[1])):10000000;
long l, LUNGIME;

105
int i = 0;
String nume=null;
File f = new File(a[0]);
LUNGIME = f.length();
in = new DataInputStream(
new FileInputStream(a[0]));

for ( l=0; l<LUNGIME ;l++ ) {
if (l % BUCATA == 0) {
if (l > 0) {
System.out.println(BUCATA+" depus in \""+nume+
"\", ramas in \""+a[0]+"\" "+(LUNGIME-l));
out.close();
} // if
i++;
nume = ""+i;
for ( ; nume.length() < 5; nume = "0"+nume);
out = new DataOutputStream(
new FileOutputStream(nume));
} // if
out.writeByte(in.readByte());
} // for

System.out.println((l%BUCATA)+" depus in \""+nume+
"\", ramas in \""+a[0]+"\" "+(LUNGIME-l));
out.close();
in.close();

} // Split.main

} // Split
Programul 2.16. Split.java

Programul pereche, Merge, adun din directorul curent toate fiierele
ale cror nume sunt iruri de cte 5 cifre reprezentnd numere ntregi conse-
cutive, ncepnd de la "00001". Iniial programul numr toate numele de
fiiere formate din 5 cifre, asta pentru a informa cte fiiere mai sunt de reunit,
dar le reunete efectiv numai pe cele consecutive. La fiecare preluare a unui nou
fiier bucat, programul d un mesaj informativ spunnd (dup socotelile lui)
cte fiiere mai sunt. Sursa Merge este dat n programul 2.17.

import java.io.*;

public class Merge {

public static void main(String a[]) throws Exception {
DataInputStream in;
DataOutputStream out = new DataOutputStream(
new FileOutputStream(a[0]));

106
int i, nrFiles = 0;
String nume = null;
File f = new File(a[0]);
long l, BUCATA, LUNGIME = f.length();
f = new File(".");
String[] sl = f.list();
for (i=0; i<sl.length; i++) {
if (sl[i].length() == 5) {
try {
Integer.parseInt(sl[i]);
nrFiles++;
} // try
catch (NumberFormatException e) {
continue;
} // catch
} // if
} // for
for ( i=1; ; i++) {
nume = ""+i;
for ( ; nume.length() < 5; nume = "0"+nume);
f = new File(nume);
if (!f.exists())
break;
BUCATA = f.length();
in = new DataInputStream(
new FileInputStream(nume));
for ( l=0; l<BUCATA ;l++ )
out.writeByte(in.readByte());
System.out.println(BUCATA+" din \""+nume+
"\" depus in \""+a[0]+"\", ramas "+(nrFiles-i)+" fisiere");
in.close();
} // for
out.close();
} // Merge.main

} // Merge
Programul 2.17. Merge.java

You might also like