Laboratorio di reti I: Java IO Stefano Brocchi [email protected] 15 ottobre, 2008 Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 1 / 28 Java IO Gli InputStream e gli OutputStream Gli stream L’astrazione di base per le comunicazioni in Java è lo stream (flusso) Le due classi di base per la gestione dell’IO sono InputStream ed OutputStream che rappresentano, rispettivamente, un flusso di dati in ingresso ed uno in uscita. Queste sono contenute nel pacchetto java.io Java OutputStream Canale InputStream Java Gli stream offrono un’interfaccia di comunicazione indipendente dal canale di comunicazione stesso Una volta creato il giusto tipo di stream, si può usare lo stesso codice per leggere e scrivere indifferentemente su vari canali File Connessione di rete Zone di memoria Standard input/output Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 2 / 28 Java IO Gli InputStream e gli OutputStream Le classi InputStream ed Outputstream Tramite gli stream si realizzano in Java la scrittura e la lettura in modo sequenziale Le classi InputStream ed OutputStream sono astratte: i metodi chiave per la lettura e la scrittura read e write non sono implementati La loro realizzazione dovrà essere fatta nelle loro sottoclassi che implementano la comunicazione su di un determinato canale FileInputStream,FileOutputStream PipedInputStream,PipedOutputStream ByteArrayInputStream,ByteArrayOutputStream Il dato di base gestito dagli stream è il byte Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 3 / 28 Java IO Gli InputStream e gli OutputStream La classe InputStream: metodi La classe InputStream offre vari metodi di base public abstract int read() throws IOException Legge un byte dallo stream, restituendolo come un intero da 0 a 255 o ritornando -1 se lo stream non può più restituire alcun valore (es. fine file). public int read(byte[] b, int off, int len) throws IOException Legge al più len bytes dallo stream scrivendoli nel vettore b a partire dalla posizione off. Restituisce il numero di byte effettivamente letti o -1 se lo stream non può più restituire alcun valore. public int read(byte[] b) throws IOException Equivalente a read (b, 0, b.length) public void close() Chiude lo stream rilasciando le risorse utilizzate Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 4 / 28 Java IO Gli InputStream e gli OutputStream La classe InputStream: metodi Altri metodi di InputStream public int available() throws IOException Restituisce il numero di byte attualmente disponibili sullo stream public void mark(int readlimit) public void reset() throws IOException public boolean markSupported() Il metodo mark permette di segnare il punto dello stream dove è arrivata la lettura; con il metodo reset si riporta la lettura al punto specificato da mark. Il metodo markSupported restituisce true se mark e reset sono effettivamente implementati nello stream utilizzato. public long skip(long n) throws IOException Salta gli n byte successivi presenti dello stream; restituisce il numero di byte effettivamente ignorati. Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 5 / 28 Java IO Gli InputStream e gli OutputStream La classe OutputStream: metodi I metodi della classe OutputStream sono perlopiù simmetrici a quelli di InputStream public abstract void write(int b) throws IOException Scrive gli otto bit meno significativi dell’intero b public void write(byte[] b) throws IOException Scrive tutti i byte contenuti in b sullo stream public void write(byte[] b, int off, int len) throws IOException Scrive len bytes sullo stream a partire dalla posizione off del vettore b Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 6 / 28 Java IO Gli InputStream e gli OutputStream La classe OutputStream: metodi public void flush() throws IOException Scrive tutti i byte passati in write sul canale di output. E’ possibile infatti che alcuni stream non scrivano immediatamente sul canale ma mantengano alcuni dati in una memoria interna; questo metodo forza la scrittura di tutti i dati passati in scrittura public void close() throws IOException Chiude il canale di output e rilascia le risorse occupate Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 7 / 28 Java IO Gli InputStream e gli OutputStream Le classi FileInputStream e FileOutputStream Due classi che realizzano gli stream sono FileInputStream e FileOutputStream, utilizzate per la scrittura e la lettura di file Nel costruttore viene specificato il nome del file a cui accedere: public FileOutputStream(String name) throws FileNotFoundException Una volta creato lo stream, questo può essere utilizzato come stream generico; il seguente codice crea (o sovrascrive) un file OutputStream out = new FileOutputStream("prova.txt"); out.write("File di prova".getBytes()); out.close(); Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 8 / 28 Java IO Gli InputStream e gli OutputStream Un esempio: copia di un file Vediamo il codice per la copia di un file try { InputStream in = new FileInputStream("source"); OutputStream out = new FileOutputStream("dest"); int b = in.read(); while (b >= 0) { out.write(b); b = in.read(); } in.close(); out.close(); } catch (IOException e) { ... } Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 9 / 28 Java IO Gli InputStream e gli OutputStream I PipedStream Un altro tipo di stream sono i PipedStream, utili per scrivere su un’area di memoria Perchè l’InputStream e l’OutputStream siano legati alla stessa area è necessario passare uno al costruttore dell’altro: PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(in); A questo punto la comunicazione può procedere tramite i soliti metodi out.write("Messaggio di prova".getBytes()); b = new byte[in.available()]; in.read(b); System.out.println(new String(b)); Essendo una zona di memoria un canale dinamico, una read su un stream vuoto resterà in attesa. Questo si può evitare chiudendo il canale di comunicazione in uscita o controllando la disponibilità dei dati prima della lettura. Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 10 / 28 Java IO Uso di classi filter per stream Classi filter Desideriamo avere delle classi che aggiungano delle funzionalità in fase di lettura o scrittura alle classi stream presenti Alcuni filtri sono: BufferedOutputStream, per scrivere l’output sempre a blocchi invece che byte per byte DataOutputStream, per la scrittura di dati ad alto livello (diversi dai byte) PrintStream, per la scritture di dati di alto livello sotto forma di sequenze di caratteri GZipOutputStream, per comprimere i dati via via che vengono scritti Per ognuna delle precedenti tranne PrintStream esiste il rispettivo InputStream Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 11 / 28 Java IO Uso di classi filter per stream Classi filter Problema: vogliamo avere delle classi che possano avere le funzionalità di varie combinazioni delle classi descritte, ma possiamo ereditare da una sola classe: FileOutputStream BufferedOutputStream DataOutputStream ? Soluzione: le classi di tipo InputStream e OutputStream vengono realizzate tramite il pattern del decorator Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 12 / 28 Java IO Uso di classi filter per stream Classi filter Le classi filter prendono un OutputStream nel costruttore e, nei loro metodi, prima effettuano le operazioni di filtraggio e dopo inoltrano l’operazione allo stream contenuto OutputStream FilterOutputStream BufferedOutputStream Stefano Brocchi DataOutputStream FileOutputStream Laboratorio di reti I: Java IO PipedOutputStream 15 ottobre, 2008 13 / 28 Java IO Uso di classi filter per stream Combinare classi di tipo OutputStream Possiamo quindi combinare liberamente stream di output OutputStream out = new FileOutputStream("outFile"); out = new BufferedOutputStream(out); DataOutputStream out2 = new DataOutputStream(out); Un’istruzione di scrittura verrà a questo punto inoltrata a tutti gli stream utilizzati write() DataOutputStream BufferedOutputStream FileOutputStream Del tutto simmetrica è la gestione degli stream di input Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 14 / 28 Java IO Uso di classi filter per stream La classe FilterOutputStream La classe FilterOutputStream, dalla quale derivano i possibili filtri, richiede nel costruttore l’OutputStream al quale si riferisce public FilterOutputStream(OutputStream out) Le classi derivanti potranno accedere a questo stream tramite il campo protetto out I metodi di FilterOutputStream inoltrano semplicemente le varie operazioni (write, close, flush...) a questo stream Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 15 / 28 Java IO Uso di classi filter per stream Realizzazione di un filtro Vediamo per esempio come si può implementare un filtro Supponiamo di voler realizzare un filtro che stampa su schermo tutto ciò che viene scritto sullo stream Si duplicano cosı̀ tutte le scritture: un metodo write scriverà contemporaneamente su schermo e sullo stream in output La classe dovrà estendere FilterOutputStream, e il suo costruttore inoltrerà la costruzione dell’oggetto a questa classe import java.io.*; public class filter extends FilterOutputStream { filter(OutputStream o) { super(o); } Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 16 / 28 Java IO Uso di classi filter per stream Realizzazione di un filtro Nel metodo write(int b) dovremo quindi Implementare il comportamento aggiuntivo del filtro Inoltrare la scrittura allo stream contenuto public void write(int b) throws IOException { System.out.print((char)b); out.write(b); } Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 17 / 28 Java IO Uso di classi filter per stream Realizzazione di un filtro Gli altri metodi write possono essere realizzati richiamando questo metodo: public void write(byte[] b, int off, int len) throws IOException { for (int i = off; i < off + len; i++) { write(b[i]); } } public void write(byte[] b) throws IOException { write(b, 0, b.length); } Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 18 / 28 Java IO Uso di classi filter per stream Realizzazione di un filtro Volendo è possibile riscrivere anche gli altri metodi, se al loro richiamo vogliamo realizzare funzionalità aggiuntive Supponiamo per esempio di voler andare a capo quando lo stream viene chiuso: public void close() throws IOException { System.out.println(); out.close(); } Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 19 / 28 Java IO Uso di classi filter per stream Realizzazione di un filtro Possiamo testare il funzionamento della classe stampando contemporaneamente su di un file e su schermo: FileOutputStream out = new FileOutputStream("test.txt"); filter f = new filter(out); f.write("Messaggio di prova".getBytes()); f.close(); Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 20 / 28 Java IO Stream forniti dal sistema Stream di sistema Alcuni stream di input ed output comunemente utilizzati sono forniti dal sistema come campi pubblici e statici della classe System InputStream in rappresentante lo standard input PrintStream out rappresentante lo standard output PrintStream err rappresentante lo standard error Gli stream di standard input, output ed error possono essere rediretti rispettivamente tramite i metodi System.setIn, System.setOut e System.setErr Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 21 / 28 Java IO Flussi di caratteri: classi Reader e Writer Le classi Reader e Writer Le classi Reader e Writer hanno lo stesso ruolo di InputStream ed OutputStream ma gestiscono stream di caratteri invece che di byte Possono essere usate per comodità nello scrivere su canali che richiedono testo collegandoli ad una classe stream tramite oggetti di tipo InputStreamReader ed OutputStreamWriter Il sistema di classi di filtraggio è identico a quello descritto per InputStream ed OutputStream Un esempio di scrittura su file: OutputStream outs = new FileOutputStream("file.txt"); Writer out = new OutputStreamWriter(outs); out = new BufferedWriter(out); out.write("File di prova"); out.close(); Le classi Reader e Writer hanno sostanzialmente gli stessi metodi di InputStream ed OutputStream Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 22 / 28 Java IO Altre classi di java.io: File e RandomAccessFile La classe File Per interfacciarsi con il filesystem Java mette a disposizione la classe File Un oggetto file rappresenta un file o una cartella; può essere creato passando al costruttore il suo nome con percorso assoluto o relativo File f = new File("../file.txt"); File f2 = new File("c:\\directory\\file.txt"); E’ inoltre possibile creare un file relativamente a un percorso iniziale, passando al costruttore il file con il percorso ed una stringa con il nome del file: File f3 = new File("c:\\"); File f4 = new File(f3, "dir\\file.txt"); // f4 e’ il file c:\dir\file.txt Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 23 / 28 Java IO Altre classi di java.io: File e RandomAccessFile La classe File Il campo statico separator contiene il separatore di percorso dipendente dal sistema (\ oppure /) Fare riferimento a questo campo per mantenere il codice indipendente dalla piattaforma String sep = File.separator; File f3 = new File("dir" + sep + "file.txt"); L’istruzione new File(".") ottiene l’oggetto rappresentante la cartella di lavoro corrente Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 24 / 28 Java IO Altre classi di java.io: File e RandomAccessFile La classe File: metodi La classe File mette a disposizione numerosi metodi per vari utilizzi: Interrogazione di proprietà del file: canRead, canWrite, exists, getName, isDirectory, length Manipolazione del file: delete, deleteOnExit, mkdir, renameTo, setLastModified Navigazione del file system: getParent, list, listFiles Per la creazione di un file temporaneo si può usare il metodo statico createTempFile(String prefix, String suffix) che crea un file nella directory temporanea di sistema con il prefisso ed il suffisso specificati Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 25 / 28 Java IO Altre classi di java.io: File e RandomAccessFile Uso della classe File: esempio Vediamo per esempio un metodo che stampa a schermo tutti i file in una cartella e nelle sue sottocartelle public static void showFiles(File dir) { File[] files = dir.listFiles(); for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { File newDir = new File(dir, files[i].getName()); showFiles(newDir); } else { System.out.println(files[i]); } } } Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 26 / 28 Java IO Altre classi di java.io: File e RandomAccessFile La classe RandomAccessFile Per l’accesso casuale ad un file esiste la classe RandomAccessFile Questa offre metodi per la lettura e scrittura anche non sequenziale Al momento della costruzione dell’oggetto si può specificare che il file verrà usato sia in fase di letture che di scrittura Es. raf = new RandomAccessFile(filename, "rw"); Le modifiche vengono fatte nella posizione indicata da un cursore manipolabile con i metodi getFilePointer, che restituisce la sua posizione, e seek, che lo posiziona nel punto indicato Disponibili metodi per la gestione di dati ad alto livello: readInt, writeInt readFloat, writeFloat readBoolean, writeBoolean readLine Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 27 / 28 Java IO Esercizio Esercizio Scrivere una classe che per ogni file con suffisso .txt presente nella cartella corrente ne crei una copia nella sottocartella uppercase con tutte le lettere maiuscole Nel caso vengano passati dei parametri alla classe scriverli nel file argomenti.txt sempre con tutte le lettere rese maiuscole Le lettere maiuscole A-Z sono codificate con i byte 65-90, le minuscole con 97-122, ordinatamente Le letture e le scritture devono venir eseguite efficientemente tramite un buffer Realizzare la classe tramite uno dei seguenti metodi: Lettura da uno stream, trasformazione del carattere e scrittura su un altro stream Implementazione di un OutputStream (o di un Writer) che, ricevendo dati rappresentanti caratteri minuscoli, scrivano caratteri maiuscoli Utilizzo della classe RandomAccessFile Stefano Brocchi Laboratorio di reti I: Java IO 15 ottobre, 2008 28 / 28