Il package java.io e i flussi
Il package java.io
„
In Java input e output sono definiti in
termini di flussi (stream)
‰
„
Due tipi di flussi
‰
‰
„
Sequenze ordinate di dati
Di dati binari (byte stream)
Di caratteri (character stream)
Ciascun tipo di flusso è gestito da
apposite classi
2
Il package java.io
„
Flussi di input: hanno una sorgente
‰
‰
„
Flussi di output: hanno una
destinazione
‰
‰
„
Per dati binari, usare la classe InputStream
Per caratteri, usare la classe Reader
Per dati binari, usare la classe OutputStream
Per caratteri, usare la classe Writer
Tutte queste classi sono nel package
java.io
‰
import java.io.*;
3
La classe IOException
„
Utilizzata da molti metodi di java.io
per segnalare condizioni eccezionali
„
Un metodo solleva una IOException
se si verifica un problema collegato al
flusso di I/O
4
Flussi Standard
Definiti dalla classe System in java.lang
„
Standard input (tastiera): System.in
„
„
Standard output (monitor): System.out
„
„
Di tipo InputStream
Di tipo PrintStream
Standard error (per messaggi di errore): System.err
„
Di tipo PrintStream
5
La classe astratta InputStream
„
Dichiara i metodi per leggere flussi
binari da una sorgente specifica
„
Alcuni metodi:
‰
public abstract int read() throws
IOException
‰
public void close() throws
IOException
6
Il metodo read
ƒ Legge un byte alla volta
ƒ Restituisce
ƒ un int (da 0 a 255) che rappresenta il byte
letto
ƒ -1 se il file è terminato
ƒ Alla fine bisogna chiudere il flusso di input
ƒ Con il metodo close()
7
Il metodo close
ƒ Chiude il flusso di input
ƒ Rilascia le risorse associate al flusso
ƒ Ulteriori operazioni sul flusso chiuso
provocano una IOException
8
La classe FileInputStream
„
Sottoclasse concreta di InputStream
‰
„
public class FileInputStream extends
InputStream
Possiamo creare oggetti di questa
classe
‰
FileInputStream in = new
FileInputStream(“nomefile.est");
9
Esempio: Contare i byte in un flusso
import java.io.*;
public class ContaByte {
public static void main(String[] args) throws
IOException {
InputStream in = new
FileInputStream(“nomefile.est”);
int totale = 0;
while (in.read() != -1)
totale++;
in.close();
System.out.println(“Il numero di byte è + ” totale);
}
}
10
Specificare il path di un file
ƒ Quando si digita il path di un file ogni
barra rovesciata va inserita due volte
ƒ Una singola barra rovesciata è un carattere
speciale!
InputStream in = new
FileInputStream(“C:\\nomedir\\nomefile.est”);
11
La classe astratta OutputStream
„
Dichiara i metodi per scrivere flussi
binari in una destinazione specifica
„
Alcuni metodi:
‰
public abstract void write(int b)
throws IOException
‰
public void close() throws
IOException
12
Il metodo write
ƒ Scrive un byte alla volta
ƒ Il byte è passato come argomento di tipo int
ƒ Alla fine bisogna chiudere il flusso di output
ƒ Con il metodo close()
13
Il metodo close
ƒ Chiude il flusso di output
ƒ Rilascia le risorse associate al flusso
ƒ Ulteriori operazioni sul flusso chiuso
provocano una IOException
14
La classe FileOutputStream
„
Sottoclasse concreta di OutputStream
‰
„
public class FileOutputStream extends
OutputStream
Possiamo creare oggetti di questa
classe
‰
FileOutputStream out = new
FileOutputStream(“nomefile.est");
15
La classe astratta Reader
„
Dichiara i metodi per leggere flussi di
caratteri da una sorgente specifica
„
Alcuni metodi:
‰
public int read() throws IOException
‰
public abstract void close() throws
IOException
16
Il metodo read
ƒ Legge un carattere alla volta
ƒ Restituisce
ƒ un int (da 0 a 65535) che rappresenta il
carattere letto
ƒ -1 se il file è terminato
ƒ Alla fine bisogna chiudere il flusso di
caratteri
ƒ Con il metodo close()
17
Il metodo close
ƒ Chiude il flusso di caratteri
ƒ Rilascia le risorse associate al flusso
ƒ Ulteriori operazioni sul flusso chiuso
provocano una IOException
18
Conversione tra flussi
„
Possiamo convertire un flusso di input
binario in un flusso di input di caratteri
„
Usiamo la classe InputStreamReader
E’ una sottoclasse concreta di Reader
‰ Il costruttore è
‰
public InputStreamReader(InputStream in)
19
Conversione tra flussi
„
Dato che l’oggetto System.in è di tipo
InputStream, possiamo convertirlo in un
flusso di caratteri
‰
InputStreamReader reader= new
InputStreamReader(System.in);
„
In generale:
InputStream in = new
FileInputStream(“nomefile.est");
InputStreamReader reader= new
InputStreamReader(in);
20
Usare un InputStreamReader
„
Gli oggetti della classe InputStreamReader
leggono un carattere per volta, ma spesso
serve leggere intere linee.
„
Abbiamo bisogno di un oggetto che compone
stringhe a partire dai caratteri letti da un
InputStreamReader
„
Possiamo usare la classe BufferedReader
„
È una sottoclasse di Reader
21
Creare un BufferedReader
„Usiamo
„
il costruttore
public BufferedReader(Reader in)
„Per
creare un oggetto che compone stringhe con i
caratteri letti da un InputStreamReader, dobbiamo
passare l’oggetto di tipo InputStreamReader al
costruttore della classe BufferedReader
‰
BufferedReader buf= new BufferedReader(reader);
22
Usare un BufferedReader
ƒ La classe BufferedReader offre vari
metodi, tra cui
ƒ String readLine() throws IOException
ƒ Legge un carattere alla volta fino ad ottenere una
linea
ƒ Quando i dati sono terminati restituisce null
23
Ricapitolando:
InputStream in = new FileInputStream (“file.est");
InputStreamReader reader = new InputStreamReader(in);
BufferedReader buf = new BufferedReader(reader);
//leggi i dati
String inputLine = buf.readLine();
24
La classe FileReader
„
Sottoclasse di InputStreamReader
‰
„
public class FileReader extends InputStreamReader
Possiamo creare oggetti di questa classe
‰
FileReader reader = new FileReader(“nomefile.txt");
25
Esempio: Contare i caratteri in un flusso
import java.io.*;
public class ContaCaratteri {
public static void main(String[] args) throws
IOException {
Reader reader = new FileReader(“nomefile.txt”);
int totale = 0;
while (reader.read() != -1)
totale++;
reader.close();
System.out.println(“Il numero di caratteri è + ”
totale);
}
}
26
Usare un FileReader
„
Gli oggetti della classe FileReader
leggono un carattere per volta, ma spesso
serve leggere intere linee.
„
Abbiamo bisogno di un oggetto che compone
stringhe a partire dai caratteri letti da un
FileReader
„
Possiamo usare la classe BufferedReader
27
Creare un BufferedReader
„Usiamo
„
il costruttore
public BufferedReader(Reader in)
„Per
creare un oggetto che compone stringhe con i
caratteri letti da un FileReader, dobbiamo passare
l’oggetto di tipo FileReader al costruttore della classe
BufferedReader
‰
BufferedReader buf= new BufferedReader(reader);
28
Ricapitolando:
FileReader reader = new FileReader(“file.txt");
BufferedReader buf = new BufferedReader(reader);
//leggi i dati
String inputLine = buf.readLine();
29
La classe astratta Writer
„
Dichiara i metodi per scrivere flussi di
caratteri in una destinazione specifica
„
Alcuni metodi:
‰
public void write(int ch) throws
IOException
‰
public abstract void close() throws
IOException
30
Il metodo write
ƒ Scrive un carattere alla volta
ƒ Il carattere è passato come argomento di
tipo int
ƒ Alla fine bisogna chiudere il flusso di
caratteri
ƒ Con il metodo close()
31
Il metodo close
ƒ Chiude il flusso di caratteri
ƒ Rilascia le risorse associate al flusso
ƒ Ulteriori operazioni sul flusso chiuso
provocano una IOException
32
Conversione tra flussi
„
Possiamo convertire un flusso di output
binario in un flusso di output di caratteri
„
Usiamo la classe OutputStreamWriter
E’ una sottoclasse concreta di Writer
‰ Il costruttore è
‰
public OutputStreamWriter(OutputStream
out)
33
Conversione tra flussi
„
L’oggetto System.out è di tipo PrintStream
„
„
„
Possiamo convertire lo standard output in un
flusso di caratteri
‰
„
PrintStream è sottoclasse di FilterOutputStream
FilterOutputStream è sottoclasse di OutputStream
OutputStreamWriter writer= new
OutputStreamWriter(System.out);
In generale:
OutputStream out = new
FileOutputStream(“nomefile.est");
OutputStreamWriter writer= new
OutputStreamWriter(out);
34
Usare un OutputStreamWriter
„
Gli oggetti della classe OutputStreamWriter
scrivono un carattere per volta, ma spesso
serve scrivere intere linee.
„
Abbiamo bisogno di un oggetto che compone
stringhe a partire dai caratteri scritti da un
OutputStreamWriter
„
Possiamo usare la classe PrintWriter
„
È una sottoclasse di Writer
35
Creare un PrintWriter
„Usiamo
„
il costruttore
public PrintWriter(OutputStream out)
„Spezza
numeri e stringhe in singoli caratteri
l’oggetto di tipo OutputStreamWriter al
costruttore della classe PrintWriter
„Passiamo
‰
PrintWriter print= new PrintWriter(writer);
36
Usare un PrintWriter
ƒ La classe PrintWriter offre vari
metodi, tra cui
ƒ void println(double x) throws
IOException
ƒ void println(String s) throws
IOException
ƒ void println(Object obj) throws
IOException
ƒ
Tali metodi invocano toString per avere una
rappresentazione in formato stringa degli oggetti
37
Ricapitolando:
OutputStream out = new FileOutputStream(“nomefile.est");
OutputStreamWriter writer= new OutputStreamWriter(out);
PrintWriter print= new PrintWriter(writer);
//scrivi i dati
print.println(“prova di scrittura”);
38
La classe FileWriter
„
Sottoclasse di OutputStreamWriter
‰
„
public class FileWriter extends OutputStreamWriter
Possiamo creare oggetti di questa classe
‰
FileWriter writer = new FileWriter(“file.txt");
39
Usare un FileWriter
„
„
Gli oggetti della classe FileWriter
scrivono un carattere per volta, ma spesso
serve scrivere intere linee.
Possiamo usare la classe PrintWriter
40
Creare un PrintWriter
„Usiamo
„
il costruttore
public PrintWriter(OutputStream out)
l’oggetto di tipo FileWriter al costruttore
della classe PrintWriter
„Passiamo
‰
PrintWriter print = new PrintWriter(writer);
41
Ricapitolando:
FileWriter writer = new FileWriter(“file.txt");
PrintWriter print = new PrintWriter(writer);
//scrivi i dati
print.println(“prova di scrittura”);
42
La classe File
ƒ
Fornisce varie operazioni per manipolare file
già esistenti
ƒ
Creiamo un oggetto di tipo
File
File inputFile = new File("input.txt");
ƒ
ƒ
Non possiamo leggere direttamente dati da un
oggetto di tipo File
Dobbiamo costruire un oggetto di tipo
FileReader
FileReader reader = new FileReader(inputFile);
43
La classe File: alcuni metodi
„ public boolean delete()
‰ Cancella il file restituendo true se la cancellazione ha
successo
„ public boolean renameTo(File newname);
‰ Rinomina il file restituendo true se la cancellazione ha
successo
„ public long length()
‰ Restituisce la lunghezza del file in byte (zero se il file non
esiste)
44
Ricapitoliamo con un esempio
import java.io.*;
public class Esempio {
public static void main(String[] args) throws IOException {
// SCRIVERE
FileWriter fw = new FileWriter("C:\\HelloWorld.txt");
PrintWriter pw = new PrintWriter(fw);
pw.println("HELLO WORLD alla fine del file");
/* Chiusura File */
pw.close();
45
Esempio
// LEGGERE
FileReader fr = new FileReader(“C:\\HelloWorld.txt");
BufferedReader br = new BufferedReader(fr);
String s = br.readLine();
/* Chiusura File */
fr.close();
System.out.println(s);
46
Esempio
File f1 = new File("C:\\HelloWorld.txt");
File f2 = new File("C:\\HelloWorld2.txt");
f1.renameTo(f2);
// Attenzione NON crea il file
File f3 = new File("C:\\HelloWorld3.txt");
// Per crearlo dovete darlo ad un Writer
FileWriter fw2 = new FileWriter(f3);
} /* Fine Main */
} /* Fine classe */
47
Flussi di Oggetti
ƒ
Consentono di memorizzare tutte le
caratteristiche di un oggetto
ƒ
ƒ
ƒ
Flussi in scrittura
Classe ObjectOutputStream
Tali caratteristiche possono essere
automaticamente ripristinate
ƒ
ƒ
Flussi in lettura
Classe ObjectInputStream
48
Vantaggi
ƒ
Per scrivere un intero oggetto
ƒ
ƒ
ƒ
Non dobbiamo prima decomporlo in altra forma
Possiamo fare una sola operazione!
Per leggere un intero oggetto
ƒ
ƒ
Non dobbiamo leggere i dati separatamente e poi
ricomporre l’oggetto
Possiamo fare una sola operazione!
49
Serializzazione
ƒ
La memorizzazione di oggetti in un flusso
viene detta serializzazione
ƒ
ƒ
ƒ
Ogni oggetto riceve un numero di serie nel flusso
Se lo stesso oggetto viene salvato due volte la
seconda volta salviamo solo il numero di serie
Due numeri di serie uguali sono interpretati come
riferimenti allo stesso oggetto
50
Serializzazione
ƒ
L’oggetto da inserire nel flusso deve
essere serializzabile
ƒ
Appartenere a una classe che implementa
l’interfaccia Serializable
ƒ Non ha metodi
51
Serializzazione
„
Per scrivere oggetti di una classe
MyClass che implementa
Serializable in un flusso di oggetti
MyClass mc = new ……
ObjectOutputStream out = new
ObjectOutputStream(new
FileOutputStream(“mc.dat”));
out.writeObject(mc);
52
Serializzazione
Per leggere oggetti di una classe
MyClass che implementa
Serializable da un flusso di oggetti
„
ObjectInputStream in = new
ObjectInputStream(new
FileInputStream(“mc.dat”));
MyClass mc =
(MyClass)in.readObject();
53
Serializzazione: readObject
ƒ
ƒ
ƒ
Legge un Object da file
Restituisce un riferimento a tale Object
L’output necessita di un cast
MyClass mc = (MyClass)in.readObject();
ƒ
Può lanciare un’eccezione controllata di tipo
ClassCastException
ƒ
Da catturare o dichiarare in una clausola
throws
54
Accesso sequenziale e casuale
ƒ Accesso sequenziale
ƒ Un file viene elaborato un byte alla
volta, in sequenza
ƒ Accesso casuale
ƒ Possiamo accedere a posizioni
arbitrarie nel file
55
Accesso sequenziale e casuale
56
Accesso sequenziale
ƒ Ogni file su disco ha un puntatore
del file posto alla fine del file
ƒ Qualsiasi dato viene aggiunto alla
fine del file
ƒ Se il puntatore viene spostato i dati
sono sovrascritti
57
Accesso casuale
ƒ Per spostare il puntatore del file,
usiamo un oggetto di tipo
RandomAccessFile
ƒ Specificando se il file deve essere aperto il
lettura (“r”) o anche in scrittura (“rw”)
RandomAccessFile f = new
RandomAccessFile("bank.dat","rw");
58
Accesso casuale
ƒ Spostiamo il puntatore del file con
il metodo seek
ƒ f.seek(n);
ƒ sposta il puntatore al byte in posizione n
ƒ f.getFilePointer();
ƒ Fornisce la posizione corrente del puntatore del
file
59