660 likes | 826 Views
IL PACKAGE java.io. Il package java.io definisce quattro classi base astratte: InputStream e OutputStream per leggere/scrivere stream di byte (come i file binari del C) Reader e Writer per leggere/scrivere stream di caratteri (da Java 1.1 in poi) (come i file di testo del C).
E N D
IL PACKAGE java.io Il package java.iodefinisce quattro classi base astratte: • InputStream e OutputStreamper leggere/scrivere stream di byte(come i file binari del C) • Readere Writer per leggere/scrivere stream di caratteri (da Java 1.1 in poi)(come i file di testo del C)
Object Reader Writer InputStream OutputStream IL PACKAGE java.io Le quattro classi base astratte di java.io
IL PACKAGE java.io Tratteremo separatamente • prima gli stream di byte • InputStream e OutputStream • poi gli stream di caratteri • Reader e Writer
STREAM DI BYTE La classe base InputStreamdefinisce metodi per: • leggere uno o più byte (read()) • sapere quanti byte sono disponibili in input (available()) • saltare N byte in input (skip()) • ricavare la posizione corrente sullo stream (mark()) e tornarci (reset()) , sempreché markSupported() sia vero.
STREAM DI BYTE La classe base OutputStreamdefinisce metodi per: • scrivere uno o più byte (write()) • svuotare il buffer di uscita (flush()) • chiudere lo stream (close())
STREAM DI BYTE Dalle classi base astratte si derivano molte classi concrete che specializzano l’I/O per: • I/O da array di byte • I/O da file • I/O filtrato • caso particolare: I/O di tipi primitivi Java (int, float, ...) • caso particolare: I/O bufferizzato • I/O di oggetti
STREAM DI BYTE - INPUT Da InputStream derivano in primis: • ByteArrayInputStream • l’input è un array di byte, passato al costruttore di ByteArrayInputStream • FileInputStream • l’input è un file, il cui nome è passato al costruttore di FileInputStream • in alternativa si può passare al costruttore un oggetto File costruito a parte, o anche un FileDescriptor
STREAM DI BYTE - INPUT Le altre classi derivate da InputStream hanno come scopo avvolgere un altro InputStreamper creare un’entità con funzionalità più evolute. Il loro costruttore ha quindi come parametro un InputStream
STREAM DI BYTE - INPUT Le due classi principali sono: • ObjectInputStream • legge oggetti serializzati salvati su stream • offre metodi per leggere i tipi primitivi e le classi standard (Integer, etc.) di Java • FilterInputStream • definisce il concetto di “filtro” • modifica il metodo read(), e se occorre anche altri, in modo da effettuare le letture in accordo al criterio di filtraggio richiesto • in pratica si usano le sue sottoclassi
STREAM DI BYTE - INPUT Le sottoclassi di FilterInputStream: • BufferedInputStream • modifica il metodo read() in modo da leggere tramite un buffer (che aggiunge) • definisce il nuovo metodo readLine(), che però è deprecato in Java 1.1 perché sostituito dalle classi Reader • DataInputStream • definisce metodi per leggere tipi di dati standard in forma binaria (readInteger(), readFloat(),..)
IL CASO DI System.in • L’oggetto statico System.in, lo standard input, è appunto un InputStream • viene praticamente sempre “avvolto” (wrapped) in un tipo di InputStream più evoluto per comodità • Ad esempio: BufferedInputStream input = new BufferedInputStream(System.in);
STREAM DI BYTE - OUTPUT Da OutputStream derivano in primis: • ByteArrayOutputStream • l’output è un array di byte interno, dinami-camente espandibile, recuperabile con i metodi toByteArray() o toString(), secondo i casi • FileOutputStream • l’output è un file, il cui nome è passato al costruttore di FileOutputStream • in alternativa si può passare al costruttore un oggetto File costruito a parte, o anche un FileDescriptor
STREAM DI BYTE - OUTPUT Le altre classi derivate da OutputStream hanno come scopo avvolgere un altro OutputStreamper creare un’entità con funzionalità più evolute. Il loro costruttore ha quindi come parametro un OutputStream
STREAM DI BYTE - OUTPUT Le due classi principali sono: • ObjectOutputStream • scrive oggetti serializzati salvati su stream • offre metodi per scrivere i tipi primitivi e le classi standard (Integer, etc.) di Java • FilterOutputStream • definisce il concetto di “filtro” • modifica il metodo write(), e se occorre anche altri, in modo da svolgere le scritture in accordo al criterio di filtraggio richiesto • in pratica si usano le sue sottoclassi
STREAM DI BYTE - OUTPUT Le sottoclassi di FilterOutputStream: • BufferedOutputStream • modifica il metodo write() in modo da scrivere tramite un buffer (che aggiunge) • DataOutputStream • fornisce metodi per scrivere in forma bina-ria tipi di dati standard (writeInteger(),..) • PrintStream • definisce metodi per stampare sotto forma di stringa i tipi primitivi (print()) e le classi standard (mediante toString())
IL CASO DI System.out • L’oggetto statico System.out, lo standard output, è appunto un OutputStream • viene praticamente sempre “avvolto” (wrapped) in un tipo di OutputStream più evoluto per comodità • Ad esempio: BufferedOutputStream output = new BufferedOutputStream(System.out);
System.in e System.out Attenzione: • Lo standard input (System.in) e lo standard output (System.out) sono in effetti stream di caratteri • Dovrebbero essere definiti comeReadereWriter, rispettivamente • Invece, sono definiti come InputStream e OutputStreamper motivi di compatibilità • in Java 1.0 Reader e Writer non c’erano
System.in e System.out Quindi, bisogna fare attenzione: • anche se definiti come InputStream e OutputStreamper motivi di compatibilità, rimangono stream di caratteri • Non ha senso scrivere su essi dati in forma binaria • in output, si vedrebbero quadratini e faccine • in input, si leggerebbero valori casuali • Si possono “trasformare” in Reader e Writer con alcune classe apposite
ESEMPIO 1 Scrittura di dati su file binario • Per scrivere su un file binario occorre un FileOutputStream, che però consente solo di scrivere un byte o un array di byte • Volendo scrivere dei float, int, double, boolean, … è molto più pratico un DataOutputStream, che ha metodi idonei • Quindi, si incapsula il FileOutputStream in un DataOutputStream
ESEMPIO 1 import java.io.*; public class Esempio1 { public static void main(String args[]){ FileOutputStream fs = null; try { fs = new FileOutputStream("Prova.dat"); } catch(IOException e){ System.out.println("Apertura fallita"); System.exit(1); } // continua...
ESEMPIO 1 (segue) DataOutputStream os = new DataOutputStream(fs); float f1 = 3.1415F; char c1 = 'X'; boolean b1 = true; double d1 = 1.4142; try { os.writeFloat(f1); os.writeBoolean(b1); os.writeDouble(d1); os.writeChar(c1); os.writeInt(12); os.close(); } catch (IOException e){ System.out.println("Scrittura fallita"); System.exit(2); } } }
ESEMPIO 2 Rilettura di dati da file binario • Per leggere da un file binario occorre un FileInputStream, che però consente solo di leggere un byte o un array di byte • Volendo leggere dei float, int, double, boolean, … è molto più pratico un DataInputStream, che ha metodi idonei • Quindi, si incapsula il FileInputStream in un DataInputStream
ESEMPIO 2 import java.io.*; public class Esempio2 { public static void main(String args[]){ FileInputStream fin = null; try { fin = new FileInputStream("Prova.dat"); } catch(FileNotFoundException e){ System.out.println("File non trovato"); System.exit(3); } // continua...
ESEMPIO 2 (segue) DataInputStream is = new DataInputStream(fin); float f2; char c2; boolean b2; double d2; int i2; try { f2 = is.readFloat(); b2 = is.readBoolean(); d2 = is.readDouble(); c2 = is.readChar(); i2 = is.readInt(); is.close(); System.out.println(f2 + ", " + b2 + ", " + d2 + ", " + c2 + ", " + i2); } catch (IOException e){ System.out.println("Errore di input"); System.exit(4); } }
IL PACKAGE java.io Stream di caratteri (Reader e Writer) • Le classi per l’I/O da stream di caratteri sono più efficienti di quelle a byte • convertono correttamentela codifica UNICODE di Java in quella locale • specifica della piattaforma in uso (tipicamente ASCII) • e della lingua in uso (essenziale per l’internazionalizzazione).
STREAM DI CARATTERI La classe base Reader definisce metodi per: • leggere uno o più caratteri (read()) • sapere se lo stream è pronto per l’input (ready()) • saltare N byte in input (skip()) • ricavare la posizione corrente sullo stream (mark()) e tornarci (reset()) , sempreché markSupported() sia vero.
STREAM DI CARATTERI La classe base Writer definisce metodi per: • scrivere uno o più caratteri (write()) • svuotare il buffer di uscita (flush()) • chiudere lo stream (close())
STREAM DI CARATTERI Dalle classi base astratte si derivano molte classi concrete che specializzano l’I/O per: • I/O da array di caratteri e da stringhe • I/Obufferizzato • I/O da stream di byte • caso particolare: I/O da file • I/O filtrato • I/O da pipe Il metodo read() restituisce caratteri UNICODE.
STREAM DI CARATTERI - INPUT Da Reader derivano in primis: • CharArrayReader • l’input è un array di caratteri, passato al costruttore di CharArrayReader • StringReader • l’input è una stringa di caratteri, passata al costruttore di StringReader • BufferedReader • l’input è un altro Reader (“wrapping”) • aggiunge la capacità di lettura bufferizzata (in particolare, un metodo readLine())
STREAM DI CARATTERI - INPUT Un caso particolarissimo di Reader è l’InputStreamReader, che reinterpreta un InputStream come un Reader • È il ponte fra il mondo dei generici stream di byte (Java 1.0) e il mondo degli stream di caratteri (Java 1.1) • Consente di “vedere” qualunque stream di byte come uno stream di caratteri • ovviamente, ha senso solo se da quello stream provengono realmente caratteri !
IL CASO DI System.in • L’oggetto statico System.in, lo standard input, è formalmente un InputStream... • ... ma in realtà è uno stream di caratteri! • Può essere “trasformato virtualmente” in un Reader incapsulandolo con un InputStreamReader • Tipicamente: InputStreamReader kbd = new InputStreamReader(System.in);
STREAM DI CARATTERI - INPUT Da InputStreamReader deriva poi FileReader • in pratica, costruisce un FileInputStream e lo incapsula in un InputStreamReader • velocizza questa operazione, consentendo di costruire direttamente un FileReader a partire dal nome del file (una stringa) • in alternativa si può passare al costruttore un oggetto File costruito a parte, o anche un FileDescriptor
STREAM DI CARATTERI - OUTPUT Da Writer derivano in primis: • CharArrayWriter • l’output è un array di caratteri • StringWriter • l’input è una stringa di caratteri • BufferedWriter • l’input è un altro Writer (“wrapping”) • aggiunge la capacità di scrittura bufferizzata
STREAM DI CARATTERI - OUTPUT Un caso particolarissimo di Writer è l’OutputStreamWriter, che reinterpreta un OutputStream come un Writer • È il ponte fra il mondo dei generici stream di byte (Java 1.0) e il mondo degli stream di caratteri (Java 1.1) • Consente di “vedere” qualunque stream di byte come uno stream di caratteri • ovviamente, ha senso solo se quello stream accetta realmente caratteri !
IL CASO DI System.out • L’oggetto statico System.out, lo standard output, è formalmente un OutputStream... • ... ma in realtà è uno stream di caratteri! • Può essere “trasformato virtualmente” in un Writer incapsulandolo con un OutputStreamWriter • Tipicamente: OutputStreamWriter video = new OutputStreamWriter(System.out);
STREAM DI CARATTERI - OUTPUT Da OutputStreamWriter deriva poi FileWriter • costruisce un FileOutputStream e lo incapsula in un OutputStreamWriter • velocizza questa operazione, consentendo di costruire direttamente un FileWriter a partire dal nome del file (una stringa) • in alternativa si può passare al costruttore un oggetto File costruito a parte, o anche un FileDescriptor
ESEMPIO 3 Scrittura di dati su file di testo • Per scrivere su un file di testo occorre un FileWriter, che però consente solo di scrivere un carattere o una stringa • Volendo scrivere dei float, int, double, boolean, … occorre convertirli in stringhe a prioricon il metodo toString() della classe corrispondente, e poi stamparli • Non esiste qualcosa di simile allo stream DataOutputStream
ESEMPIO 3 import java.io.*; public class Esempio3 { public static void main(String args[]){ FileWriter fout = null; try { fout = new FileWriter("Prova.txt"); } catch(IOException e){ System.out.println("Apertura fallita"); System.exit(1); } float f1 = 3.1415F; char c1 = 'X'; boolean b1 = true; double d1 = 1.4142;
ESEMPIO 3 (segue) try { String buffer = null; buffer = Float.toString(f1); fout.write(buffer,0,buffer.length()); buffer = new Boolean(b1).toString(); fout.write(buffer,0,buffer.length()); buffer = Double.toString(d1); fout.write(buffer,0,buffer.length()); fout.write(c1); // singolo carattere buffer = Integer.toString(12); fout.write(buffer,0,buffer.length()); fout.close(); } catch (IOException e){...} } }
ESEMPIO 3 - note • Il nostro esempio ha stampato sul file le rappresentazioni sotto forma di stringa di svariati valori... • ... ma non ha inserito spazi intermedi ! • Ha perciò scritto: 3.1415true1.4142X12
ESEMPIO 4 Rilettura di dati da file di testo • Per leggere da un file di testo occorre un FileReader, che però consente solo di leggere un carattere o una stringa • Occorre quindi un ciclo che legga carat-tere per carattere fino alla fine del file • il metodo ready() restituisce true finché ci sono altri caratteri da leggere • il metodo read() restituisce il carattere letto sotto forma di int, perché -1 indica l’EOF
ESEMPIO 4 import java.io.*; public class Esempio4 { public static void main(String args[]){ FileReader fin = null; try { fin = new FileReader("Prova.txt"); } catch(FileNotFoundException e){ System.out.println("File non trovato"); System.exit(3); } // continua...
ESEMPIO 4 (segue) try { while(fin.ready()){ char ch = (char) fin.read(); System.out.print(ch); // echo } System.out.println(""); } catch (IOException e){ System.out.println("Errore di input"); System.exit(4); } }
ESEMPIO 3 - UNA VARIANTE • La versione precedente ha stampato sul file le rappresentazioni sotto forma di stringa di svariati valori, ma non ha inserito spazi intermedi • Aggiungiamo uno spazio fra i valori, in modo da stampare • non più 3.1415true1.4142X12 • ma 3.1415 true 1.4142 X 12
ESEMPIO 3 - VARIANTE try { String buffer = null; buffer = Float.toString(f1) + " "; fout.write(buffer,0,buffer.length()); buffer = new Boolean(b1).toString() + " "; fout.write(buffer,0,buffer.length()); buffer = Double.toString(d1) + " "; fout.write(buffer,0,buffer.length()); fout.write(c1); // singolo carattere fout.write(' '); buffer = Integer.toString(12) + " "; fout.write(buffer,0,buffer.length()); fout.close(); } ...
ESEMPIO 4 - UNA VARIANTE • La versione precedente ha letto dal file un’unica stringa ininterrotta • non poteva far altro, mancando gli spazi • Ora però gli spazi fra i valori ci sono:ergo, possiamo definire una funzione statica readField() che legga un campo fino al successivo spazio • non può essere un metodo, perché esso dovrebbe far parte della classe FileReader, che non possiamo modificare
ESEMPIO 4 - readField() static public String readField(Reader in){ StringBuffer buf = new StringBuffer(); boolean nospace = true; try { while(in.ready() && nospace){ char ch = (char)in.read(); nospace = (ch!=' '); if (nospace) buf.append(ch); } } catch (IOException e){ System.out.println("Errore di input"); System.exit(4); } return buf.toString(); }
L’ESEMPIO 4 RIFORMULATO // continua... try { while(fin.ready()){ String s = readField(fin); System.out.println(s); // echo } } catch (IOException e){ System.out.println("Errore di input"); System.exit(4); } }