Nella scorsa lezione abbiamo visto gli stream a basso livello, flussi di caratteri, con le classi InputStream ed OutputStream, questa volta parleremo dell’invio, su un generico canale di comunicazione, degli altri tipi primitivi e non solo caratteri, quindi vedremo gli stream ad alto livello. Dal momento che finora abbiamo lavorato a basso livello, ci aspettiamo che ci siano altre classi che si appoggino a InputStream ed OutputStream in modo da inviare stringhe, numeri interi ed altri tipi. In pratica lo strato intermedio dovrà essere in grado di filtrare le richieste espresse ad alto livello e sminuzzarle per renderle comprensibili alle funzioni di basso livello che abbiamo visto nella lezione precedente. Nella realtà questo ruolo è svolto dalle classi derivanti da FilterOutputStream e FilterInputStream contenute nel package java.io: per la precisione si tratta di DataOutputStream e DataInputStream, derivate dalle precedenti.
La classe DataOutputStream deriva da FilterOutputStream che a sua volta deriva da OutputStream. Per quanto riguarda il filtro c’é da dire che non si discosta molto dalla classe base, in pratica basta passargli uno stream a basso livello nel costruttore per istanziarlo. L’altra invece, oltre a riprendere totalmente il comportamento della prima, implementa l’interfaccia DataOutput che fornisce un’implementazione per questi metodi:
- void wite(int b) throws IOException
- void write(byte b[]) throws IOException
- void write(byte b[], int off, int len) throws IOException
- void writeBoolean(boolean v) throws IOException
- void writeByte(int v) throws IOException
- void writeShort(int v) throws IOException
- void writeChar(int v) throws IOException
- void writeInt(int v) throws IOException
- void writeLong(long v) throws IOException
- void writeFloat(float v) throws IOException
- void writeDouble(double v) throws IOException
- void writeBytes(String s) throws IOException
- void writeChars(String s) throws IOException
- void writeUTF(String s) throws IOException
Si può osservare che per ogni tipo primitivo di Java esiste la funzione corrispondente. Vediamo un esempio pratico per capire come funziona il tutto.
import java.io.*; public class Main { public static void main(String[] args) { String s = "Ciao a tutti!\n"; DataOutputStream d = new DataOutputStream(System.out); try { d.writeChars(s); d.writeBytes(s); d.writeUTF(s); } catch (Exception e) { } } }
La prima cosa strana che si nota è la creazione di uno stream per mandare i dati sullo standard output ( stdout ), in questo caso si dice che i due flussi sono collegati “in cascata”. Se fate partire il programma noterete che la stringa viene stampata in maniera differente per ognuna delle funzioni utilizzate.
DataInputStream è la simmetrica di DataOutputStream ed i metodi che espone l’interfaccia DataInput potete trovarli in qualsiasi aiuto in linea della documentazione del JDK. Ora infatti, capito il funzionamento di Java, dovreste essere in grado di cercare da soli i vari metodi che le classi o interfacce espongono ( anche perché negli IDE evoluti come NetBeans alla scrittura del punto della classe appaiono tutti i metodi molto ben commentati ).
Una prassi comunemente seguita è quella di identificare il dispositivo di output o input sempre a nostra completa disposizione, questo si può tranquillamente creare attraverso l’uso di un buffer di memoria, quindi i dati inviati al dispositivo andranno prima in un buffer e poi, quando questo sarà pieno, verrà svuotato nel dispositivo vero e proprio; ovviamente per l’input si deve ragionare al contrario. La classe di output che si occupa di gestire i dati bufferizzati è BufferedOutputStream che deriva da FilterOutputStream, analogamente BufferedInputStream derivererà da FilterInputStream. Vediamo quindi l’esempio precedente utilizzando i buffer:
import java.io.*; public class Main { public static void main(String[] args) { String s = "Ciao a tutti!\n"; DataOutputStream d = new DataOutputStream( new BufferedOutputStream(System.out)); try { d.writeChars(s); d.writeBytes(s); d.writeUTF(s); d.flush(); } catch (Exception e) { } } }
Come potete notare abbiamo inserito uno stream bufferizzato in OutpuStream ed alla fine delle scritture su buffer dobbiamo svuotarlo con il metodo flush. L’utilità di questa tecnica può essere apprezzata su canali di comunicazione di rete quali Internet, in cui gli scambi di informazioni avvengono in tempi molto più lunghi rispetto ai canali locali.
<< Lezione Precedente – Inizio Corso – Lezione Successiva >>