Fluxurile de intrare \ ieşire reprezintă mecanismele prin
intermediul cărora programele java pot citi \ scrie date de la şi
către diverse destinaţii (fişiere, alte programe, memorie,
resurse de reţea, dispozitive etc.).
Un flux este un canal de comunicaţie unidirecţional prin
intermediul căruia datele pot fi citite sau scrise.
Prin intermediul fluxurilor de intrare datele sunt citite. Prin
intermediul fluxurilor de ieşire datele sunt transmise către o
destinaţie.
Figura 1. Fluxurile de intrare şi ieşire.
În java există două tipuri de fluxuri: fluxuri orientate pe
byte şi fluxuri orientate pa caracter.
Fluxurile orientate pe byte sunt folosite in general pentru scrierea
şi citirea de date binare (imagini, sunete, obiecte, etc), array-uri de
date.
Figura 1. Fluxurile din citire \ scriere orientate pe
byte.
Fluxurile de citire orientate pe byte au la bază clasa InputStream
iar fluxurile de scriere au la baza clasa OutputStream.
Fluxurile orientate pe caracter au fost introduse in versiunea 1.1. a
java şi sunt destinate pentru manipularea şirurilor de caractere
(scrierea şi citirea se face pe 16 biţi).
Figura 2. Fluxurile de citire \ scriere orientate pe
caracter.
Fluxurile de citire orientate pe caracter au la bază clasa Reader
iar fluxurile de scriere au la baza clasa Writer.
Pentru majoritatea programelor scrierea si citirea datelor se va face
prin intermediul fluxurilor de caractere deoarece acestea permit manipularea
caracterelor Unicode (16-biti), În timp ce fluxurile de
octeţi permit doar lucrul pe 8 biţi.
Aplicaţia următore exemplifică modul în care fluxurile de
intrare ieşire pot fi folosite pentru scrierea şi citirea de date din
cadrul aplicaţiilor java.
import java.io.*;
public class IOStreamDemo {
public static void main(String[]
args)
throws IOException {
// 1.
BufferedReader in = new BufferedReader(
new FileReader(".project"));
String s, s2 = new String();
while((s = in.readLine())!= null)
s2 += s + "\n";
in.close();
// 1b.
BufferedReader stdin = new BufferedReader(
new InputStreamReader(System.in));
System.out.print("Enter a line:");
System.out.println(stdin.readLine());
// 2. Input
from memory
StringReader in2 = new StringReader(s2);
int c;
while((c = in2.read()) != -1)
System.out.print((char)c);
// 3.
Formatted memory input
try {
DataInputStream in3 = new DataInputStream(
new ByteArrayInputStream(s2.getBytes()));
while(true)
System.out.print((char)in3.readByte());
} catch(EOFException e) {
System.err.println("End of stream");
}
// 4. File
output
try {
BufferedReader in4 = new BufferedReader(
new StringReader(s2));
PrintWriter out1 = new PrintWriter(
new BufferedWriter(new FileWriter("IODemo.out")));
int lineCount = 1;
while((s = in4.readLine()) != null )
out1.println(lineCount++ + ": " + s);
out1.close();
} catch(EOFException e) {
System.err.println("End of stream");
}
// 5. Storing
& recovering data
try {
DataOutputStream out2 = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("Data.txt")));
out2.writeDouble(3.14159);
out2.writeUTF("That was pi");
out2.writeDouble(1.41413);
out2.writeUTF("Square root of 2");
out2.close();
DataInputStream in5 = new DataInputStream(
new BufferedInputStream(
new FileInputStream("Data.txt")));
// Must use
DataInputStream for data:
System.out.println(in5.readDouble());
// Only
readUTF() will recover the
// Java-UTF
String properly:
System.out.println(in5.readUTF());
// Read the
following double and String:
System.out.println(in5.readDouble());
System.out.println(in5.readUTF());
} catch(EOFException e) {
throw new
RuntimeException(e);
}
// 6.
Reading/writing random access files
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("Value " + i + ": " +
rf.readDouble());
rf.close();
}
În cadrul clasei System sunt definite fluxurile standard de intrare /
ieşire System.in (in este un atribut static de tip InputStream definit în
cadrul clasei System) şi System.out (out este un atribut static de tip
OutputStream definit în cadrul clasei System) care sunt conectate în mod
implicit la ecran respectiv tastatură. Exemplu următor prezintă
modul în care poate fi folosit fluxul de intrare standard pentru citirea
datelor. Pe lângă aceste două fluxuri în
cadrul clasei System este definit şi fluxul err (atribut static de tip
OutputStream definit în cadrul clasei System) care poate fi folosit pentru
raportarea mesajelor de eroare.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
public class StandardIOExemplu {
static String sortChars(String s){
char[] a = s.toCharArray();
Arrays.sort(a);
return new String(a);
}
public static void
main(String[] args) {
try{
BufferedReader fluxIn = new BufferedReader(new InputStreamReader(System.in));
String linie = "";
do{
System.out.print(">");
linie = fluxIn.readLine();
System.out.println("result:"+sortChars(linie));
}while(linie.indexOf("end")==-1);
}catch(Exception e){
e.printStackTrace();
System.err.println("Eroare
:"+e.getMessage());
}
}
}
Fluxurile standard pot fi redirectate folosind metodele
setOut(), setIn() şi setErr() din cadrul clasei System.
import java.io.*;
class Redirectare {
public static void
main(String[] args) {
try {
BufferedInputStream in = new BufferedInputStream(
new FileInputStream(".project"));
PrintStream out = new PrintStream(new
BufferedOutputStream(
new FileOutputStream("test.out")));
System.setIn(in);
System.setOut(out);
System.setErr(out);
BufferedReader br
= new BufferedReader(
new InputStreamReader(System.in));
String s;
while((s = br.readLine()) != null)
System.out.println(s);
out.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
Serializarea este macanismul prin care starea obiectelor poate fi
citită din memorie şi trimisă printr-un flux către o
destinaţie (o altă aplicaţie, fişier, reţea, etc.).
Procesul invers prin care un obiect este reîncărcat în memorie prin citirea
acestuia dintr-un flux se numeşte deserializare. Pentru serilaizarea
şi deserializarea obiectelor limbajul java pune la dispoziţie
fluxurile ObjectInputStream şi ObjectOutputStream.
import java.util.*;
import java.io.*;
public class SerializareExemplu {
public static void
main(String[] args) throws
Exception{
AlienFactory f = new AlienFactory();
Alien a =
f.createAlien("axx");
Alien b =
f.createAlien("abb");
f.freezAlien(a,"aliena.dat");
f.freezAlien(b,"alienb.dat");
Alien x = f.unfreezAlien("alienb.dat");
Alien y =
f.unfreezAlien("aliena.dat");
System.out.println(x);
System.out.println(y);
}
}//.class
class AlienFactory{
Alien createAlien(String
name){
Alien z = new Alien(name);
System.out.println(z+"
is alive.");
return z;
}
void freezAlien(Alien a, String
storeRecipientName) throws
IOException{
ObjectOutputStream o =
new ObjectOutputStream(
new FileOutputStream(storeRecipientName));
o.writeObject(a);
System.out.println(a+":I'll
be back.");
}
Alien unfreezAlien(String
storeRecipientName) throws
IOException, ClassNotFoundException{
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream(storeRecipientName));
Alien x = (Alien)in.readObject();
System.out.println(x+":I'm back.");
return x;
}
}//.class
class Alien implements Serializable{
String name;
transient int id;
public Alien(String n) {
this.name = n;
id =
(int)(Math.random()*100);
}
public void move(){System.out.println("Alien is moving."+this);}
public String toString(){return "[alien="+name+":id="+id+"]";}
}//.class
Pentru implementarea mecanismului de serializare / deserializare se
poate folosi şi interfaţa Externalizable ce permite controlul mai fin
al procesului de salvare şi încărcare a obiectelor. Această
interfaţă extinde interfaţa Serializable şi defineşte
metodele writeExternal() şi readExternal() în cadrul cărora trebui
implementat codul pentru scrierea şi citire obiectelor. Clasa ce
implementează această interfaţă trebuie obligatoriu să
aibă definit constructorul implicit (având specificatorul de acces
public).
Dacă se doreşte ca un anumit atribut al unui obiect serializat
să nu fie salvat atunci se poate folosi cuvântul cheie transient în faţa declaraţiei
atributului respecitv.
package isp.fluxuri.serializare;
import java.util.*;
import java.io.*;
public class SerializareExemplu2 {
public static void
main(String[] args) {
Tren tr = new Tren();
Locomotiva l = new Locomotiva("XYZ", new Engine("diesel"));
Vagon v1 = new Vagon(1,20);
Vagon v2 = new Vagon(2,89);
Vagon v3 = new Vagon(3,53);
tr.addVagon(v1);tr.addVagon(v2);tr.addVagon(v3);
tr.addLocomotiva(l);
System.out.println(tr);
tr.save("trenX");
try {
Tren t2 = Tren.load("trenX");
System.out.println(t2);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Tren implements Serializable{
LinkedList t = new LinkedList();
transient int id;
Tren(){
id = (int)(Math.random()*1000);
}
void addVagon(Vagon v){
t.addLast(v);
}
void addLocomotiva(Locomotiva e){
t.addFirst(e);
}
void save(String fileName) {
try {
ObjectOutputStream
o =
new ObjectOutputStream(
new FileOutputStream(fileName));
o.writeObject(this);
System.out.println("Tren
salvat in fisier");
} catch (IOException e) {
System.err.println("Trenul
nu poate fi scris in fisiser.");
e.printStackTrace();
}
}
static Tren load(String fileName) throws IOException, ClassNotFoundException {
ObjectInputStream
in =
new ObjectInputStream(
new FileInputStream(fileName));
Tren t =
(Tren)in.readObject();
return t;
}
public String toString(){
String x="Tren ID="+id+" ";
for (Iterator i = t.iterator(); i.hasNext();) {
Object element =
(Object) i.next();
x+=element;
}
return x;
}
}
class Vagon implements Externalizable{
int nr;
int nrPasageri;
public Vagon(){}
public Vagon(int i,int p) {
nr=i;
nrPasageri = p;
}
@Override
public String toString() {
return "<"+nr+" pasageri="+nrPasageri+">";
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
nr = in.readInt();
nrPasageri=in.readInt();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(nr);
out.writeInt(nrPasageri);
}
}
class Locomotiva implements Serializable{
String marca;
Engine e;
/**
* @param marca
* @param e
*/
public Locomotiva(String marca, Engine e) {
this.marca = marca;
this.e = e;
}
@Override
public String toString() {
return "[Locomotiva"+marca+" "+e+"]";
}
}
class Engine implements Serializable{
String tip;
public Engine(String t) {
tip = t;
}
@Override
public String toString() {
return "-"+tip+"-";
}
}
Fluxurile de tip pipe sunt folosite pentru a trimite date intre
două componente ale aceluiaşi program. Utilitatea acestor tipuri de
fluxuri va deveni evidentă în momentul în care se va discuta despre fire
de execuţie şi aplicaţii multifir. Limbajul java permite
construirea de pipe-uri orientate pe byte folosind clasele PipedInputStream /
PipedOutputStream şi fluxuri orientate pe caracter folosind clasele PipedReader
/ PipedWriter.
import java.io.*;
public class Piped2Example {
public static void
main(String[] args) {
try{
PipedReader in = new PipedReader();
PipedWriter out = new PipedWriter();
in.connect(out);
//scrie date in pipe
out.write("mesaj scris in pipe");
//citeste din pipe
while(in.ready()){
int x = in.read();
System.out.println("Read
from pipe:"+(char)x);
}
}catch(Exception e){
e.printStackTrace();
}
}
}//.
În cadrul pachetului java.util.zip sunt definite fluxuri de intrare ieşire
ce permit comprimarea şi decomprimarea datelor. Programul următor
exemplifică modul în care poate fi comprimat / decomprimat un fişier.
package isp.fluxuri.bytes;
import java.io.*;
import java.util.zip.*;
public class ZipUtil {
void compressFile(String source, String dest){
try {
// Create the
GZIP output stream
String outFilename = dest;
GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(outFilename));
// Open the
input file
String inFilename = source;
FileInputStream in = new FileInputStream(inFilename);
// Transfer
bytes from the input file to the GZIP output stream
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
// Complete
the GZIP file
out.finish();
out.close();
} catch (IOException e) {
System.out.println("Error
compressing file:"+e.getMessage());
}
}
void decompressFile(String source, String
dest){
try {
// Open the
compressed file
String inFilename = source;
GZIPInputStream in = new GZIPInputStream(new FileInputStream(inFilename));
// Open the output file
String outFilename = dest;
OutputStream out = new FileOutputStream(outFilename);
// Transfer
bytes from the compressed file to the output file
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Close the
file and stream
in.close();
out.close();
} catch (IOException e) {
System.out.println("Error
decompressing file:"+e.getMessage());
}
}
void generateFile(String name, long size){
try {
FileOutputStream
s = new
FileOutputStream(new
File(name));
for(int i=0;i<size;i++){
int c = (int)(40+Math.random()*50);
s.write(c);
}
} catch (FileNotFoundException e) {
// TODO
Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO
Auto-generated catch block
e.printStackTrace();
}
}
public static void
main(String[] args) {
ZipUtil zu = new ZipUtil();
zu.generateFile("test.txt", 1024);
zu.compressFile("test.txt", "test.gzip");
zu.decompressFile("test.gzip","decompressed.txt");
}
}