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