10/10/20021 Ingresso e uscita in Java F. Bombi 10 ottobre 2002
10/10/20022 I flussi di ingresso e uscita Il pacchetto java.io definisce le operazioni di ingresso e uscita in termini di flussi (stream). I flussi sono sequenze ordinate di dati che hanno una sorgente (flussi di ingresso) o una destinazione (flussi di uscita) Le classi di java.io nascondono i dettagli del sistema operativo sottostante e dei dispositivi di ingresso e uscita coinvolti dalle operazioni di ingresso e uscita
10/10/20023 Caratteri e byte I flussi di ingresso e uscita possono essere – flussi di caratteri (character stream) composti da caratteri Unicode codificati con 16 bit, le classi che realizzano i flussi di caratteri sono indicate come lettori (reader) scrittori (writer) – flussi di byte (byte stream) composti da byte di 8 bit, le classi che realizzano i flussi di byte sono indicate come flussi di ingresso (input stream) flussi di uscita (output stream)
10/10/20024 Byte e Caratteri Si utilizzeranno byte stream quando si voglia elaborare informazione di tipo binario oppure quando si voglia elaborare, un carattere alla volta, file composti da caratteri rappresentati con un solo byte ciascuno secondo la codifica ASCII Si utilizzeranno reader e writer quando si voglia elaborare informazione di tipo testuale. È possibile convertire uno stream in un reader o in writer in modo che un testo Unicode sia trasformato in un flusso di byte un carattere per byte e viceversa
10/10/20025 Errori È sempre possibile che un’operazione di ingresso o uscita non vada a buon fine. Ad esempio si può cercare di aprire un file che non esiste oppure cercare di scrivere su di un file protetto in scrittura o leggere un file protetto in lettura. Gli errori di ingresso e uscita sono segnalati in due modi: in qualche caso l’errore è segnalato cambiando lo stato dello stream, più frequentemente l’errore è segnalato lanciando un’eccezione di tipo IOException che deve essere catturata o passata al programma chiamante
10/10/20026 Ingresso da file binari Per leggere un file in formato binario si utilizza un oggetto della classe FileInputStream Un file di cui si conosca il nome come stringa di caratteri si apre invocando il costruttore: FileInputStream in = new FileInputStream(nome); Per leggere un byte si utilizza il metodo read() che restituisce un int con il byte letto inserito negli 8 bit meno significativi All’ EOF il metodo read() restituisce il valore –1 Al termine delle operazioni di ingresso il file deve essere chiuso invocando il metodo close()
10/10/20027 Uscita su file binari Per scrivere un file in formato binario si utilizza un oggetto della classe FileOutputStream Il file in uscita viene aperto invocando il costruttore: FileOutputStream out = new FileOutputStream(nome); che crea il file individuato dalla stringa nome se non esiste o azzera il file se esiste Per scrivere un byte si utilizza il metodo write(int c). Il metodo usa un solo parametro int del quale verranno trasferiti in usciti gli 8 bit meno significativi Al termine delle operazioni di uscita il file deve essere chiuso, per assicurarsi che il contenuto dei buffer di sistema sia effettivamente trasferito sul file, invocando il metodo close()
10/10/20028 // Copia2.java import java.io.*; public class Copia2 { public static void main (String[] arg) throws IOException { FileInputStream in = new FileInputStream(arg[0]); FileOutputStream out = new FileOutputStream(arg[1]); int c = in.read(); while (c != -1) { out.write(c); c = in.read(); } out.close(); } $ java Copia2 f1 f2
10/10/20029 Lettore o Reader Per accedere ad un file di testo si userà un reader aprendo il file con il costruttore: FileReader lettore = new FileReader(nome); Il lettore consente di leggere un carattere alla volta con il metodo read(), è in genere più comodo leggere una riga alla volta convertendo il lettore in un BufferedReader con il costruttore: BufferedReader in = new BufferedReader(lettore); Il BufferedReader dispone del metodo readLine() che restituisce in una stringa un’intera riga letta dal file (privata del fineriga) All’ EOF il metodo realLine() restituisce un riferimento null
10/10/ Scrittore o Writer Per scrivere un file di testo si userà un writer aprendo il file con il costruttore: FileWriter scrittore = new FileWriter(nome); Lo scrittore consente di scrivere un carattere alla volta con il metodo write(c), è in genere più comodo disporre delle funzionalità di un PrintWriter creato con il costruttore: PrintWriter out = new PrintWriter(scrittore); Il PrintWriter dispone dei metodi print(arg) e println(arg) che convertono l’argomento in una stringa per poi trasferirla in uscita eventualmente con l’aggiunta di un fineriga
10/10/ Che cosa è il fineriga? Un file di testo è un file composto da caratteri (nel nostro caso da caratteri di un byte secondo la codifica ASCII) Il file è diviso in righe cioè in sequenze di caratteri terminati dalla stringa fineriga Il fineriga dipende dal sistema operativo – “\r\n”Windows – “\n”Unix – Linux – “\r”MAC OS Per generare un fineriga da tastiera si usa una sequenza di controllo – Ctr cWindows – Ctr dUnix
10/10/ Flussi standard La macchina virtuale Java eredita dal sistema operativo tre flussi già aperti che vengono passati a metodo main() : – System.in ingresso standard di tipo InputStream normalmente connesso alla tastiera del posto di lavoro – System.out uscita standard di tipo PrintStream normalmente connesso con la finestra di lavoro – System.err uscita standard per i messaggi d’errore di tipo PrintStream normalmente connesso con la finestra di lavoro Ingresso e uscite standard dovrebbero essere dei reader e dei writer, sono stati definiti come stream nella versione 1.0 di JDK prima dell’introduzione dei flussi di caratteri nel pacchetto java.io. L’uso della classe PrintStream è deprecated (tollerato per compatibilità all’indietro) e in pratica usato solo con System.out e System.err.
10/10/ Dirottamento dei flussi standard La shell Unix e analogamente il prompt di comandi Windows consentono di dirottare (file redirection) l’ingresso e l’uscita standard rispettivamente dalla tastiera ad un file e dallo schermo verso un file È possibile trasformare l’ingresso standard in un InputStreamReader e successivamente in un BufferedReader. In questo modo è possibile leggere dall’ingresso una riga alla volta con il metodo readLine() molto più comodo del metodo read() che richiede di leggere un carattere alla volta e di gestire il fineriga (diverso da sistema a sistema)
10/10/ Flussi standard Tastiera file applicazione schermo file System.in System.out System.err Parametri della riga di comando schermo < >
10/10/ Copia.java import java.io.*; public class Copia { public static void main (String[] arg) throws IOException {InputStreamReader lettore = new InputStreamReader(System.in); BufferedReader in = new BufferedReader(lettore); String str = in.readLine(); while (str != null) { System.out.println(str); str = in.readLine(); } $ java Copia $ java Copia >nomeFile $ java Copia <nomeFile $ java Copia f2
10/10/ // Crea.java import java.io.*; public class Crea { public static void main (String[] arg) throws IOException { FileOutputStream out = new FileOutputStream(arg[0]); int n = Integer.parseInt(arg[1]); for (int i = 0; i < n; i++) out.write(i); out.close(); } $ java Crea file lunghezza
10/10/ // Dump.java -- esamina il contenuto di un file binario import java.io.*; public class Dump { public static void main (String[] arg) throws IOException { FileInputStream in = new FileInputStream(arg[0]); int n = Integer.parseInt(arg[1]); int c = 0; int i = 0; String str = Integer.toString(i); while (str.length() < 4) str = " " + str; System.out.print(str); String car = " "; while (((c = in.read()) != -1) && (i < n)) { str = Integer.toString(c); while (str.length() < 4) str = " " + str; System.out.print(str); i++; if (c < 31) car += '.'; // i caratteri di controllo diventano un punto else if (c < 128) car += (char)c; // caratteri ASCII else car += '*'; // eventuali caratteri > 127 diventano *
10/10/ if (i % 10 == 0) // ogni 10 caratteri un fineriga { System.out.println(car); car = " "; str = Integer.toString(i); while (str.length() < 4) str = " " + str; System.out.print(str); } // Dump.ja va -- esam ina il con tenuto di !"#$%&' ()*+,-./01