Input / Output Spesso un programma deve acquisire dati da una sorgente esterna o inviare informazioni a una destinazione esterna. L’informazione puo’ essere di ogni tipo: caratteri, immagini, suoni, oggetti. 1 Input / Output Stream di Input / Output Per acquisire dati, un programma apre uno stream associato alla sorgente di informazione (file, socket, memoria, ecc.) e legge l’informazione sequenzialmente da esso. In modo analogo, un programma puo’ inviare verso una destinazione esterna dei dati aprendo uno stream associato alla destinazione e scrivendovi in modo sequenziale i dati. Indipendentemente dall’origine e dalla destinazione dei dati e dal loro tipo, gli algoritmi per leggere e scrivere sequenzialmente dei dati sono gli stessi. 2 Stream di Input / Output 3 Input / Output Lettura Scrittura Apertura dello stream Finché e’ presente informazione leggi l’informazione Chiudi lo stream Apertura dello stream Finché e’ presente informazione scrivi l’informazione Chiudi lo stream 4 Tipi di Stream Le classi di gestione degli stream si dividono sono di due tipi in base al tipo di dato su cui operano. Stream di Caratteri: classi Reader e Writer Stream di Byte: classi InputStream e OutputStream (di solito usati per leggere file di immagini e suoni). Le classi InputStreamReader e OutputStreamWriter consentono di trasformare stream di byte in stream di caratteri. Un InputStreamReader legge byte e li converte in caratteri. Le classi BufferedReader e BufferedWriter vengono utilizzate per leggere/scrivere blocchi di dati (caratteri a 16 bit) riducendo cosi’ il numero di accessi alla sorgente/destinazione. BufferedReader(Reader in) BufferedWriter(Writer out) 5 Gestione di Stream di caratteri 6 Gestione di Stream di byte 7 La classe System Talvolta un programma richiede l’accesso alle risorse del sistema, allo standard output, allo standard input, ecc. La piattaforma Java consente di effettuare l’accesso alle risorse del sistema attraverso l’uso della classe System. La classe System fornisce lo stream in (di tipo InputStream) associato allo standard input, lo stream out associato allo output e lo stream err associato allo standard error. Inoltre contiene alcuni metodi che svolgono diversi compiti. Ad esempio il metodo currentTimeMillis() fornisce il tempo in millisecondi (a partire dal 1/1/1970), il metodo exit(int status) interrompe l’interpretazione del programma, ecc. 8 FileReader Normalmente un flusso viene creato a partire da un file su disco. Per interagire con un file di caratteri occorre quindi creare un oggetto di tipo FileReader FileReader(String fileName) esistono anche altri costruttori Esempio: FileReader in = new FileReader(“nome-file”); 9 java.lang.Object | +--java.io.Reader | +--java.io.InputStreamReader | +--java.io.FileReader FileReader public FileReader(String fileName) throws FileNotFoundException Crea un nuovo FileReader, per leggere dal file il cui nome viene passato come parametro. Parametri: FileName – nome del file da leggere Throws: FileNotFoundException – se il file specificato non esiste 10 BufferedReader Un BufferedReader permette di gestire un flusso tramite un buffer: I dati vengono letti a blocchi dal flusso e memorizzati in un buffer Quando viene richiesto un nuovo dato prima si verifica la sua disponibilità nel buffer, se non disponibile si legge un nuovo blocco Costruttori disponibili BufferedReader(Reader in) Crea un oggetto BufferedReader a partire da un oggetto Reader Metodi disponibili in aggiunta a quelli di Reader String readLine() Legge una riga e la restituisce sotto forma di stringa 11 Copia di un file 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. // dal java-tutorial import java.io.*; public class Copy { public static void main(String[] args) { FileReader in = new FileReader(args[0]); FileWriter out = new FileWriter(args[1]); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } } 12 Copia di un file Copy.java:7: Exception java.io.FileNotFoundException must be caught, or it must be declared in the throws clause of this method. FileReader in = new FileReader(args[0]); ^ Copy.java:8: Exception java.io.IOException must be caught, or it must be declared in the throws clause of this method. FileWriter out = new FileWriter(args[1]); ^ 2 errors 13 Copia di un file 1. import java.io.*; 2. 3. public class Copy { 4. public static void main(String[] args) { 5. try { 6. FileReader in = new FileReader(args[0]); 7. FileWriter out = new FileWriter(args[1]); 8. 9. int c; 10. while ((c = in.read()) != -1) 11. out.write(c); 12. } 13. catch(FileNotFoundException e) { 14. System.err.println(e); 15. System.exit(1); 16. } 17. catch(IOException e) { 18. System.err.println(e); 19. System.exit(1); 20. } 21. … 14 Copia di un file Copy.java:19: : Exception java.io.IOException must be caught, or it must be declared in the throws clause of this method. while ((c = in.read()) != -1) ^ 1 error 15 Copia di un file 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. // dal java-tutorial import java.io.*; public class Copy { public static void main(String[] args) throws IOException { FileReader in = new FileReader(args[0]); FileWriter out = new FileWriter(args[1]); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } } 16 Copia di un file 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. // dal java-tutorial import java.io.*; public class CopyBytes { public static void main(String[] args) throws IOException { FileInputStream in = new FileInputStream(args[0]); FileOutputStream out = new FileOutputStream(args[1]); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } } 17 PrintStream La classe PrintStream mette a disposizione i metodi print e println utilizzabili con qualunque tipo di parametro. Si può creare un nuovo oggetto PrintStream a partire da un OutputStream, in particolare da un FileOutputStream. PrintStream f = new PrintStream( new FileOutputStream(“nome-file”) ); Gli oggetti System.out e System.err sono di tipo PrintStream 18 Classe File Serve per ottenere informazioni riguardo un file, non tratta file aperti Nota bene: Creare un oggetto ti tipo File non significa creare un file fisico Costruttori disponibili File(String pathname) Crea un oggetto di tipo File a partire da una stringa (il pathname) File(File parent, String child) Crea un oggetto di tipo File avente come nome child a partire dalla directory parent (descritta tramite un oggetto di tipo File) File(String parent, String child) Crea un oggetto di tipo File avente come nome child a partire dalla directory parent 19 Proprietà di un file 1. import java.io.File; 2. 3. public class FileInfo { 4. 5. public static void main(String[] args) 6. throws java.io.IOException { 7. File f = new File("FileInfo.class"); 8. System.out.println(f.exists()); 9. System.out.println(f.isFile()); 10. System.out.println(f.isDirectory()); 11. System.out.println(f.canRead()); 12. System.out.println(f.canWrite()); 13. System.out.println(f.length()); 14. System.out.println(f.getAbsolutePath()); 15. System.out.println(f.getName()); 16. System.out.println(f.getParent()); 17. File p = new File(f.getAbsolutePath()); 18. System.out.println(p.getParent()); 19. } 20. } true true false true True 919 E:\Prove\FileInfo.class FileInfo.class null E:\Prove 20 File Metodi disponibili boolean delete() Cancella il file o la directory specificata boolean mkdir() Crea la directory boolean renameTo(File dest) Cambia nome al file String[] list() Restituisce un vettore con i nomi dei file della directory riferita dall’oggetto File File[] listFiles() Restituisce un vettore con gli oggetti File che fanno riferimento ai file della directory riferita dall’oggetto File … 21 Listato di una directory 1. import java.io.File; 2. 3. public class Lista { 4. 5. public static void main(String[] args) { 6. File workingDir = new File("."); 7. String[] lista = workingDir.list(); 8. for(int i=0; i<lista.length; i++) { 9. System.out.println(lista[i]); 10. } 11. } 12. 13. } Lista.java Lista.class Copy.java Provare a creare un equivalente del comando ls -l Copy.class FileInfo.java FileInfo.class 22 Eccezioni Un’eccezione è un oggetto che descrive una situazione inusuale o erronea. Le eccezioni vengono lanciate da un programma o dalla macchina virtuale, e possono, se lo si desidera essere intercettate e gestite. Si puo’ gestire un’eccezione nei seguenti tre modi: Non gestire l’eccezione; Gestire l’eccezione non appena si verifica; Gestire l’eccezione in un altro punto del programma. 23 Gestione delleEccezioni Se un’eccezione viene ignorata dal programma, allora il programma stesso verra’ interrotto producendo un messaggio di errore opportuno. Il messaggio include il tipo di eccezione lanciata e la pila delle chiamate che consentono di individuare il punto del programma in cui l’eccezione si e’ verificata. 24 Il blocco try Per gestire un’eccezione occorre inserire l’istruzione che puo’ lanciare l’eccezione all’interno di un blocco try. Un blocco try e’ seguito da una o piu’ clausole catch che contengono le istruzioni che servono a gestire la/e eccezione/i. Ogni clausola catch e’ associata ad un tipo di eccezione. Ogni blocco try puo’ avere piu’ clausole catch associate. Ogni clausola catch viene detta gestore di eccezioni. Quando viene eseguito un blocco try, vengono eseguite tutte le istruzioni contenute nel blocco. Se non si verificano eccezioni, l’esecuzione continua poi con le istruzioni che seguono il blocco try (dopo la clausola catch). Se si verifica un’eccezione all’interno di un blocco try, il controllo passa al gestore di eccezioni appropriato. Dopo l’esecuzione delle istruzioni della clausola catch, il controllo passa alle istruzioni che seguono l’intero blocco try - catch. 25 Gestione delle eccezioni Se un’eccezione non viene intercettata e gestita quando si verifica, il controllo viene immediatamente restituito al metodo che ha invocato il metodo che l’ha prodotta. Le eccezioni si propagano finchè si incontra un metodo che intercetta e gestisce l’eccezione, oppure finchè non termina anche il metodo main. Per intercettare un’eccezione ad un livello piu’ esterno, il metodo che produce l’eccezione deve essere invocato all’interno di un blocco try che possieda la clausola catch appropriata per gestirla. Le eccezioni possono essere lanciate da un metodo al chiamante con la clausola throws che segue l’intestazione della definizione del metodo. La clausola throws serve per indicare che quel metodo puo’ lanciare o propagare una particolare eccezione, se si verifica. public static void main(String[] args) throws IOException { 26 Eccezioni controllate Le eccezioni controllate richiedono che il metodo in cui si possono verificare le intercetti e le gestisca direttamente o le elenchi nella clausola throws. 27 1. import java.io.*; 2. 3. public class ProvaEccezione { 4. 5. private String d; 6. 7. public ProvaEccezione(String dati) { 8. d = dati; 9. } 10. 11. public static ProvaEccezione[] leggiFile(String fileName) 12. throws IOException { 13. ProvaEccezione[] dati = new ProvaEccezione[50]; 14. 15. File f = new File(fileName); 16. if(!f.canRead()) { 17. throw new IOException("Il file "+fileName+" non e' leggibile"); 18. } 19. BufferedReader in = new BufferedReader(new FileReader(f)); 20. for(int i=0; i<dati.length; i++) { 21. String line = in.readLine(); 22. if(line == null) throw new EOFException( 23. "Incontrato EOF durante la lettura di "+fileName); 24. dati[i] = new ProvaEccezione(line); 25. } 26. in.close(); 27. return dati; 28. } 29. } Esempio di eccezioni 28 Esempio di eccezioni 1. import java.io.*; 2. 3. public class ProvaEccezione { 4. 5. public static final String 6. msg = "Durante la lettura si e' incontrato il seguente errore:\n“, 7. prompt = "vuoi leggere un altro file? "; 8. 9. public static void main(String[] args) { 10. String fileName = args.length>0 ? args[0] : "ProvaEccezione.java"; 11. while(fileName != null && fileName.length()>0) { 12. try { 13. leggiFile(fileName); 14. break; 15. } 16. catch(IOException e) { 17. System.out.println(msg+e.getMessage()); 18. fileName = MyUtility.readLine(prompt).trim(); 19. } 20. } 21. } 22. 23. } 29 Clausola finally Al blocco try si puo’ associare la clausola opzionale finally che definisce una sezione di codice che viene eseguita indipendentemente da come si sia usciti dal blocco try. Spesso si utilizza per gestire risorse o per garantire che alcune parti dell’algoritmo vengano eseguite comunque. 30 Classe StringTokenizer La classe StringTokenizer class e’ definita nel package java.util. Un oggetto StringTokenizer separa una stringa in sottostringhe dette token. Per default, il tokenizer separa la stringa ad ogni spazio. Il costruttore StringTokenizer richiede come parametro la stringa da separare. Ciascuna chiamata al metodo nextToken restituisce il token successivo. 31 public void write () { PrintWriter out = null; try { out = new PrintWriter(new FileWriter("OutFile.txt")); for (int i = 0; i < n; i++) out.println("Value at: " + i + " = " + v[i]); } catch (ArrayIndexOutOfBoundsException e) { System.err.println("ArrayIndexOutOfBoundsException: " + e.getMessage()); } catch (IOException e) { System.err.println("IOException: " + e.getMessage()); } finally { if (out != null) { System.out.println("Closing PrintWriter"); out.close(); } else { System.out.println("PrintWriter not open"); } } } 32 // MyUtility import java.io.*; public class MyUtility { private static BufferedReader console=new BufferedReader(new InputStreamReader(System.in)); public static String readLine(String prompt) { try { System.out.println(prompt); return console.readLine(); } catch(IOException e) { System.err.println(e); System.exit(1); } return null; } } 33