Laboratorio di reti I: Java IO
Stefano Brocchi
[email protected]
15 ottobre, 2008
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
1 / 28
Java IO
Gli InputStream e gli OutputStream
Gli stream
L’astrazione di base per le comunicazioni in Java è lo stream (flusso)
Le due classi di base per la gestione dell’IO sono InputStream ed
OutputStream che rappresentano, rispettivamente, un flusso di dati
in ingresso ed uno in uscita. Queste sono contenute nel pacchetto
java.io
Java
OutputStream
Canale
InputStream
Java
Gli stream offrono un’interfaccia di comunicazione indipendente dal
canale di comunicazione stesso
Una volta creato il giusto tipo di stream, si può usare lo stesso codice
per leggere e scrivere indifferentemente su vari canali
File
Connessione di rete
Zone di memoria
Standard input/output
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
2 / 28
Java IO
Gli InputStream e gli OutputStream
Le classi InputStream ed Outputstream
Tramite gli stream si realizzano in Java la scrittura e la lettura in
modo sequenziale
Le classi InputStream ed OutputStream sono astratte: i metodi
chiave per la lettura e la scrittura read e write non sono
implementati
La loro realizzazione dovrà essere fatta nelle loro sottoclassi che
implementano la comunicazione su di un determinato canale
FileInputStream,FileOutputStream
PipedInputStream,PipedOutputStream
ByteArrayInputStream,ByteArrayOutputStream
Il dato di base gestito dagli stream è il byte
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
3 / 28
Java IO
Gli InputStream e gli OutputStream
La classe InputStream: metodi
La classe InputStream offre vari metodi di base
public abstract int read() throws IOException
Legge un byte dallo stream, restituendolo come un intero da 0 a 255
o ritornando -1 se lo stream non può più restituire alcun valore (es.
fine file).
public int read(byte[] b, int off, int len) throws
IOException
Legge al più len bytes dallo stream scrivendoli nel vettore b a partire
dalla posizione off. Restituisce il numero di byte effettivamente letti
o -1 se lo stream non può più restituire alcun valore.
public int read(byte[] b) throws IOException
Equivalente a read (b, 0, b.length)
public void close()
Chiude lo stream rilasciando le risorse utilizzate
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
4 / 28
Java IO
Gli InputStream e gli OutputStream
La classe InputStream: metodi
Altri metodi di InputStream
public int available() throws IOException
Restituisce il numero di byte attualmente disponibili sullo stream
public void mark(int readlimit)
public void reset() throws IOException
public boolean markSupported()
Il metodo mark permette di segnare il punto dello stream dove è
arrivata la lettura; con il metodo reset si riporta la lettura al punto
specificato da mark. Il metodo markSupported restituisce true se
mark e reset sono effettivamente implementati nello stream
utilizzato.
public long skip(long n) throws IOException
Salta gli n byte successivi presenti dello stream; restituisce il numero
di byte effettivamente ignorati.
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
5 / 28
Java IO
Gli InputStream e gli OutputStream
La classe OutputStream: metodi
I metodi della classe OutputStream sono perlopiù simmetrici a quelli
di InputStream
public abstract void write(int b) throws IOException
Scrive gli otto bit meno significativi dell’intero b
public void write(byte[] b) throws IOException
Scrive tutti i byte contenuti in b sullo stream
public void write(byte[] b, int off, int len) throws
IOException
Scrive len bytes sullo stream a partire dalla posizione off del vettore
b
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
6 / 28
Java IO
Gli InputStream e gli OutputStream
La classe OutputStream: metodi
public void flush() throws IOException
Scrive tutti i byte passati in write sul canale di output. E’ possibile
infatti che alcuni stream non scrivano immediatamente sul canale ma
mantengano alcuni dati in una memoria interna; questo metodo forza
la scrittura di tutti i dati passati in scrittura
public void close() throws IOException
Chiude il canale di output e rilascia le risorse occupate
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
7 / 28
Java IO
Gli InputStream e gli OutputStream
Le classi FileInputStream e FileOutputStream
Due classi che realizzano gli stream sono FileInputStream e
FileOutputStream, utilizzate per la scrittura e la lettura di file
Nel costruttore viene specificato il nome del file a cui accedere:
public FileOutputStream(String name) throws
FileNotFoundException
Una volta creato lo stream, questo può essere utilizzato come stream
generico; il seguente codice crea (o sovrascrive) un file
OutputStream out = new FileOutputStream("prova.txt");
out.write("File di prova".getBytes());
out.close();
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
8 / 28
Java IO
Gli InputStream e gli OutputStream
Un esempio: copia di un file
Vediamo il codice per la copia di un file
try {
InputStream in = new FileInputStream("source");
OutputStream out = new FileOutputStream("dest");
int b = in.read();
while (b >= 0) {
out.write(b);
b = in.read();
}
in.close();
out.close();
} catch (IOException e) { ... }
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
9 / 28
Java IO
Gli InputStream e gli OutputStream
I PipedStream
Un altro tipo di stream sono i PipedStream, utili per scrivere su
un’area di memoria
Perchè l’InputStream e l’OutputStream siano legati alla stessa area è
necessario passare uno al costruttore dell’altro:
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream(in);
A questo punto la comunicazione può procedere tramite i soliti metodi
out.write("Messaggio di prova".getBytes());
b = new byte[in.available()];
in.read(b);
System.out.println(new String(b));
Essendo una zona di memoria un canale dinamico, una read su un
stream vuoto resterà in attesa. Questo si può evitare chiudendo il
canale di comunicazione in uscita o controllando la disponibilità dei
dati prima della lettura.
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
10 / 28
Java IO
Uso di classi filter per stream
Classi filter
Desideriamo avere delle classi che aggiungano delle funzionalità in
fase di lettura o scrittura alle classi stream presenti
Alcuni filtri sono:
BufferedOutputStream, per scrivere l’output sempre a blocchi invece
che byte per byte
DataOutputStream, per la scrittura di dati ad alto livello (diversi dai
byte)
PrintStream, per la scritture di dati di alto livello sotto forma di
sequenze di caratteri
GZipOutputStream, per comprimere i dati via via che vengono scritti
Per ognuna delle precedenti tranne PrintStream esiste il rispettivo
InputStream
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
11 / 28
Java IO
Uso di classi filter per stream
Classi filter
Problema: vogliamo avere delle classi che possano avere le
funzionalità di varie combinazioni delle classi descritte, ma possiamo
ereditare da una sola classe:
FileOutputStream
BufferedOutputStream
DataOutputStream
?
Soluzione: le classi di tipo InputStream e OutputStream vengono
realizzate tramite il pattern del decorator
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
12 / 28
Java IO
Uso di classi filter per stream
Classi filter
Le classi filter prendono un OutputStream nel costruttore e, nei loro
metodi, prima effettuano le operazioni di filtraggio e dopo inoltrano
l’operazione allo stream contenuto
OutputStream
FilterOutputStream
BufferedOutputStream
Stefano Brocchi
DataOutputStream
FileOutputStream
Laboratorio di reti I: Java IO
PipedOutputStream
15 ottobre, 2008
13 / 28
Java IO
Uso di classi filter per stream
Combinare classi di tipo OutputStream
Possiamo quindi combinare liberamente stream di output
OutputStream out = new FileOutputStream("outFile");
out = new BufferedOutputStream(out);
DataOutputStream out2 = new DataOutputStream(out);
Un’istruzione di scrittura verrà a questo punto inoltrata a tutti gli
stream utilizzati
write()
DataOutputStream
BufferedOutputStream
FileOutputStream
Del tutto simmetrica è la gestione degli stream di input
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
14 / 28
Java IO
Uso di classi filter per stream
La classe FilterOutputStream
La classe FilterOutputStream, dalla quale derivano i possibili filtri,
richiede nel costruttore l’OutputStream al quale si riferisce
public FilterOutputStream(OutputStream out)
Le classi derivanti potranno accedere a questo stream tramite il
campo protetto out
I metodi di FilterOutputStream inoltrano semplicemente le varie
operazioni (write, close, flush...) a questo stream
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
15 / 28
Java IO
Uso di classi filter per stream
Realizzazione di un filtro
Vediamo per esempio come si può implementare un filtro
Supponiamo di voler realizzare un filtro che stampa su schermo tutto
ciò che viene scritto sullo stream
Si duplicano cosı̀ tutte le scritture: un metodo write scriverà
contemporaneamente su schermo e sullo stream in output
La classe dovrà estendere FilterOutputStream, e il suo costruttore
inoltrerà la costruzione dell’oggetto a questa classe
import java.io.*;
public class filter extends FilterOutputStream {
filter(OutputStream o) {
super(o);
}
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
16 / 28
Java IO
Uso di classi filter per stream
Realizzazione di un filtro
Nel metodo write(int b) dovremo quindi
Implementare il comportamento aggiuntivo del filtro
Inoltrare la scrittura allo stream contenuto
public void write(int b) throws IOException {
System.out.print((char)b);
out.write(b);
}
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
17 / 28
Java IO
Uso di classi filter per stream
Realizzazione di un filtro
Gli altri metodi write possono essere realizzati richiamando questo
metodo:
public void write(byte[] b, int off, int len)
throws IOException {
for (int i = off; i < off + len; i++) {
write(b[i]);
}
}
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
18 / 28
Java IO
Uso di classi filter per stream
Realizzazione di un filtro
Volendo è possibile riscrivere anche gli altri metodi, se al loro
richiamo vogliamo realizzare funzionalità aggiuntive
Supponiamo per esempio di voler andare a capo quando lo stream
viene chiuso:
public void close() throws IOException {
System.out.println();
out.close();
}
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
19 / 28
Java IO
Uso di classi filter per stream
Realizzazione di un filtro
Possiamo testare il funzionamento della classe stampando
contemporaneamente su di un file e su schermo:
FileOutputStream out = new FileOutputStream("test.txt");
filter f = new filter(out);
f.write("Messaggio di prova".getBytes());
f.close();
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
20 / 28
Java IO
Stream forniti dal sistema
Stream di sistema
Alcuni stream di input ed output comunemente utilizzati sono forniti
dal sistema come campi pubblici e statici della classe System
InputStream in rappresentante lo standard input
PrintStream out rappresentante lo standard output
PrintStream err rappresentante lo standard error
Gli stream di standard input, output ed error possono essere rediretti
rispettivamente tramite i metodi System.setIn, System.setOut e
System.setErr
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
21 / 28
Java IO
Flussi di caratteri: classi Reader e Writer
Le classi Reader e Writer
Le classi Reader e Writer hanno lo stesso ruolo di InputStream ed
OutputStream ma gestiscono stream di caratteri invece che di byte
Possono essere usate per comodità nello scrivere su canali che
richiedono testo collegandoli ad una classe stream tramite oggetti di
tipo InputStreamReader ed OutputStreamWriter
Il sistema di classi di filtraggio è identico a quello descritto per
InputStream ed OutputStream
Un esempio di scrittura su file:
OutputStream outs = new FileOutputStream("file.txt");
Writer out = new OutputStreamWriter(outs);
out = new BufferedWriter(out);
out.write("File di prova");
out.close();
Le classi Reader e Writer hanno sostanzialmente gli stessi metodi di
InputStream ed OutputStream
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
22 / 28
Java IO
Altre classi di java.io: File e RandomAccessFile
La classe File
Per interfacciarsi con il filesystem Java mette a disposizione la classe
File
Un oggetto file rappresenta un file o una cartella; può essere creato
passando al costruttore il suo nome con percorso assoluto o relativo
File f = new File("../file.txt");
File f2 = new File("c:\\directory\\file.txt");
E’ inoltre possibile creare un file relativamente a un percorso iniziale,
passando al costruttore il file con il percorso ed una stringa con il
nome del file:
File f3 = new File("c:\\");
File f4 = new File(f3, "dir\\file.txt");
// f4 e’ il file c:\dir\file.txt
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
23 / 28
Java IO
Altre classi di java.io: File e RandomAccessFile
La classe File
Il campo statico separator contiene il separatore di percorso
dipendente dal sistema (\ oppure /)
Fare riferimento a questo campo per mantenere il codice indipendente
dalla piattaforma
String sep = File.separator;
File f3 = new File("dir" + sep + "file.txt");
L’istruzione new File(".") ottiene l’oggetto rappresentante la
cartella di lavoro corrente
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
24 / 28
Java IO
Altre classi di java.io: File e RandomAccessFile
La classe File: metodi
La classe File mette a disposizione numerosi metodi per vari utilizzi:
Interrogazione di proprietà del file: canRead, canWrite, exists,
getName, isDirectory, length
Manipolazione del file: delete, deleteOnExit, mkdir, renameTo,
setLastModified
Navigazione del file system: getParent, list, listFiles
Per la creazione di un file temporaneo si può usare il metodo statico
createTempFile(String prefix, String suffix) che crea un
file nella directory temporanea di sistema con il prefisso ed il suffisso
specificati
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
25 / 28
Java IO
Altre classi di java.io: File e RandomAccessFile
Uso della classe File: esempio
Vediamo per esempio un metodo che stampa a schermo tutti i file in
una cartella e nelle sue sottocartelle
public static void showFiles(File dir) {
File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
File newDir = new File(dir, files[i].getName());
showFiles(newDir);
} else {
System.out.println(files[i]);
}
}
}
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
26 / 28
Java IO
Altre classi di java.io: File e RandomAccessFile
La classe RandomAccessFile
Per l’accesso casuale ad un file esiste la classe RandomAccessFile
Questa offre metodi per la lettura e scrittura anche non sequenziale
Al momento della costruzione dell’oggetto si può specificare che il file
verrà usato sia in fase di letture che di scrittura
Es. raf = new RandomAccessFile(filename, "rw");
Le modifiche vengono fatte nella posizione indicata da un cursore
manipolabile con i metodi getFilePointer, che restituisce la sua
posizione, e seek, che lo posiziona nel punto indicato
Disponibili metodi per la gestione di dati ad alto livello:
readInt, writeInt
readFloat, writeFloat
readBoolean, writeBoolean
readLine
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
27 / 28
Java IO
Esercizio
Esercizio
Scrivere una classe che per ogni file con suffisso .txt presente nella
cartella corrente ne crei una copia nella sottocartella uppercase con
tutte le lettere maiuscole
Nel caso vengano passati dei parametri alla classe scriverli nel file
argomenti.txt sempre con tutte le lettere rese maiuscole
Le lettere maiuscole A-Z sono codificate con i byte 65-90, le
minuscole con 97-122, ordinatamente
Le letture e le scritture devono venir eseguite efficientemente tramite
un buffer
Realizzare la classe tramite uno dei seguenti metodi:
Lettura da uno stream, trasformazione del carattere e scrittura su un
altro stream
Implementazione di un OutputStream (o di un Writer) che, ricevendo
dati rappresentanti caratteri minuscoli, scrivano caratteri maiuscoli
Utilizzo della classe RandomAccessFile
Stefano Brocchi
Laboratorio di reti I: Java IO
15 ottobre, 2008
28 / 28