Java I/O e serializzazione
Caratteristiche dell I/O in Java Diverse classi per gestire I/O differenti sotto un unica struttura. Possibilita di combinare classi differenti. Modalita di interazione distinte in termini di byte o caratteri.
Classe InputStream Viene ereditata da tutte le classi che rappresentano uno stream in lettura. Fornisce i seguenti metodi: 1 int available(); //Optional 2 void close(); //releases system resources 3 int read(); //reads next byte 4 int read(byte[] b); //read some bytes and stores in b 5 int read(byte[] b, int off, int len); //attempts to read len byte and stores in b from off 6 long skip(long n); // skips and discards n bytes
Classe OutputStream Viene ereditata da tutte le classi che rappresentano uno stream in scrittura. Fornisce i seguenti metodi: 1 void close(); 2 void flush();//force any buffered output byte to be written 3 void write(int b); //writes byte b 4 void write(byte[] b); //writes all bytes in b 5 void write(byte[] b, int off, int len); //writes len byte of b starting from b[off]
Classi FileInputStream e FileOutputStream Implementano lettura e scrittura di file. Costruttori: 1 FileInputStream(File file); //creates an input stream, by opening a connection to File 2 FileInputStream(String name); //creates an input stream, by opening a connection to path 3 4 FileOutputStream(File file) //creates a stream from File 5 FileOutputStream(File file, boolean append); //appends content to the end of file 6 FileOutputStream(String name);//creates a stream from Path 7 FileOutputStream(String name, boolean append);
Classe ByteArrayInputStream Tratta un array di byte come un input. usato quando voglio memorizzare in memoria read-only Costruttori: 1 ByteArrayInputStream(byte[] buf); //Creates a ByteArrayInputStream so that it uses buf as its buffer array. 2 ByteArrayInputStream(byte[] buf, int offset, int length); Metodi: 1 read(); //Reads the next byte of data from this input stream.
Classe ByteArrayOutputStream Tratta un array di byte come un output. usato quando voglio memorizzare in memoria read-only e possibile scrivere nello stream con i seguenti metodi: 1 write(int b); //writres b in 2 write(byte[] b, int off, int len); //writes len byte of b starting from b[off] 3 writeto(outputstream out); //writes the output stream e possibile ottenere l array di byte contenente l output tramite: 1 byte[] tobytearray(); //Crea un array contentente l output scritto nello stream.
BufferedInputStream e BufferedOutputStream Queste classi aggiungono un buffer ad un InputStream/OutputStream dato. Inoltre BufferedInputStream aggiunge le funzionalita di mark e reset allo stream. mark: fissa una posizione nel buffer reset: torna alla posizione fissata da mark 1 bufferedinputstream.mark(100); 2 //read no more than 100 bytes... 3 bufferedinputstream.reset(); // reset back to marked position
Classe DataInputStream Aggiunge funzionalita ad un input stream. restituisce tipi java base gia convertiti Fornisce i seguenti metodi: 1 DataInputStream(InputStream in); 2 3 boolean readboolean(); 4 byte readbyte(); 5 char readchar(); 6 double readdouble(); 7 float readfloat(); 8 int readint(); 9 long readlong(); 10 short readshort(); 11 int readunsignedbyte(); 12 int readunsignedshort(); 13 String readutf(); 14 static String readutf(datainput in);
Classe DataOutputStream Aggiunge funzionalita ad un output stream. scrive direttamente tipi java base Fornisce i seguenti metodi: 1 DataOutputStream(OutputStream out); 2 3 void writeboolean(boolean v); 4 void writebyte(int v); 5 void writebytes(string s); 6 void writechar(int v); 7 void writechars(string s); 8 void writedouble(double v); 9 void writefloat(float v); 10 void writeint(int v); 11 void writelong(long v); 12 void writeshort(int v); 13 void writeutf(string str);
Reader e Writer Finora abbiamo operato direttamente su sequenze di byte. e possibile ragionare in termini di caratteri tramite le classi Reader e Writer. Tali classi rappresentano un input stream in termini di caratteri. non implementano input/output stream
Classe Reader Viene ereditata da tutte le classi che rappresentano uno stream di caratteri in lettura. Fornisce i seguenti metodi: 1 void close(); //Closes the stream and releases any system resources associated with it. 2 int read(); //Reads a single character. 3 int read(char[] cbuf); //Reads characters into an array. 4 int read(char[] cbuf, int off, int len); //Reads characters into a portion of an array. 5 int read(charbuffer target); //Attempts to read characters into the specified character buffer. 6 boolean ready(); //Tells whether this stream is ready to be read. 7 void mark(int readaheadlimit) //mark position, keep buffer for readaheadlimit char 8 void reset(); //Resets the stream. 9 long skip(long n); //Skips characters.
Classe Writer Viene ereditata da tutte le classi che rappresentano uno stream di caratteri in scrittura. Fornisce i seguenti metodi: 1 void close(); //Closes the stream, flushing it first. 2 void flush(); //Flushes the stream. 3 void write(char[] cbuf); //Writes an array of characters. 4 void write(char[] cbuf, int off, int len); //Writes a portion of an array of characters. 5 void write(int c); //Writes a single character. 6 void write(string str); //Writes a string. 7 void write(string str, int off, int len); //Writes a portion of a string.
Come passare da I/O su byte a I/O su caratteri? Le classi OutputStreamWriter e InputStreamReader fanno da ponte tra le due. Queste costruiscono un Reader/Writer partendo da un InputStrem/OutputStream. e possibile fornire la codifica da utilizzare, altrimenti verra usata quella di default.
Classe Scanner Questa classe fornisce metodi utili per parsare un input. Fornisce i seguenti metodi: 1 String findinline(string pattern); 2 String findwithinhorizon(string pattern, int horizon); 3 boolean hasnext(); 4 String next(); 5 String next(string pattern); 6 boolean nextboolean(); 7 byte nextbyte(); 8 double nextdouble(); 9 float nextfloat(); 10 int nextint(); 11 String nextline(); 12 Scanner skip(string pattern); 13 Scanner usedelimiter(string pattern);
Classe PrintWriter Questa classe fornisce metodi utili per stampare un output testuale. Fornisce i seguenti metodi: 1 void print(boolean b); 2 void print(char c); 3 void print(char[] s); 4 void print(double d); 5 void print(float f); 6 void print(int i); 7 void print(long l); 8 void print(object obj); 9 void print(string s); 10 PrintWriter printf(locale l, String format, Object... args); 11 void println(); 12 void println(...); //Stessi metodi di print
Mappa degli stream http://quarkphysics.ca/ics4u1/unit2-fileio/oreilly_fileio.ht
Esercizio CSV Si implementi un lettore di file comma-separated values (CSV) Per semplicita si ipotizzi che i caratteri virgola e a capo non siano presenti all interno di alcun valore Fornisce i seguenti metodi: 1 public interface CSVReader { 2 3 public Map<String, String> getrow(int index);//ritorna una riga ( mappa tra i nomi del campo nell intestazione e il valore della riga) 4 5 public int size(); //Ritorna il numero di righe presenti 6 7 }
Esercizio magic number Si vuole identificare se un determinato file e un eseguibile ELF o meno Per semplicita si consideri solo il magic number presente all inizio
Serializzazione Permette di memorizzare, trasmettere via rete una struttura dati
Cosa puo essere serializzato? Tipi primitivi, stringhe e istanze di classi serializzabili Riferimenti e classi che rappresentano risorse di sistema (Socket, File,... ) NON possono essere serializzate.
Riferimenti La serializzazione genera una rappresentazione dei dati copiando il contenuto degli oggetti, non i loro riferimenti! Con la deserializzazione otteniamo dei nuovi oggetti, diversi da quelli originali ma con lo stesso valore
Esempio di classe serializzabile 1 public class Person implements Serializable{ 2 3 private static final long serialversionuid = 382104422531955291L; 4 5 private final String name; 6 7 private final Calendar birthday; 8 9 } Implementa Serializable Contiene solo tipi primitivi/oggetti serializzabili
serialversionuid Identifica la versione della classe serializzata Serve per controllare la compatibilita tra diverse versioni della stessa classe che potrebbero avere attributi diversi
Serializzazione Si effettua tramite il metodo writeobject della classe ObjectOutputStream Questo metodo serializza l oggetto passato come parametro e lo scrive su uno stream di uscita
Esempio di serializzazione 1 public static void main(string[] args) throws IOException, ClassNotFoundException { 2 Person person = new Person("Mario", new GregorianCalendar(1990, 11, 20)); 3 ByteArrayOutputStream os = new ByteArrayOutputStream(); 4 ObjectOutputStream out = new ObjectOutputStream(os); 5 out.writeobject(person); //Serializzo 6 }
Deserializzazione Si effettua tramite il metodo readobject della classe ObjectInputStream Questo metodo deserializza il primo oggetto presente nello stream di ingresso Attenzione: Oltre agli errori dovuti alla lettura dallo stream e possibile ottenere una ClassNotFoundException se la classe dell oggetto da deserializzare non viene trovata nel classpath.
Esempio completo di serializzazione 1 public static void main(string[] args) throws IOException, ClassNotFoundException { 2 Person person = new Person("Mario", new GregorianCalendar(1990, 11, 20)); 3 ByteArrayOutputStream os = new ByteArrayOutputStream(); 4 ObjectOutputStream out = new ObjectOutputStream(os); 5 out.writeobject(person); //Serializzo 6 7 ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); 8 ObjectInputStream in = new ObjectInputStream(is); 9 Person p = (Person)in.readObject(); //Deserializzo 10 }
Attributi transient e possibile specificare come transient attributi che non e possibile (o utile) serializzare Tali attributi vengono ignorati dalla serializzazione La deserializzazione (di default) non inizializza gli attributi transient, che assumono il valore null non e pero possibile modificare il metodo di deserializzazione ridefinendo readobject (analogamente posso ridefinire writeobject)
Esempio di attributi transient 1 public class Person implements Serializable{ 2 private static final long serialversionuid = 382104422531955291L; 3 private final String name; 4 private final Calendar birthday; 5 private transient int age; 6 7 // Posso ridefinire come viene serializzato l oggetto sullo stream 8 private void writeobject(objectoutputstream out) throws IOException { 9 out.defaultwriteobject(); //Utilizzo il comportamento di default 10 } 11 12 // Posso ridefinire come viene deserializzato l oggetto dallo stream 13 private void readobject(objectinputstream in) throws ClassNotFoundException, IOException{ 14 in.defaultreadobject(); //Utilizzo il comportamento di default 15 //Qui posso inizializzare eventuali attributi transient 16 age = computeage(); 17 } 18 }
Ack Slide originarie di Alessandro Rizzi, modificate da Mattia Salnitri