JAVA - I/O System
Il JAVA considera tutte i flussi da e verso l’esterno,
come stream di byte. Questi possono essere di
ingresso o di uscita:
1.
InputStream: Flusso di byte in ingresso. Con questa
classe è possibile sia leggere il singolo byte, che un certo
numero indicato.
2.
OutputStream: Flusso di byte in uscita. Anche con questa
classe è possibile sia scrivere il singolo byte, che un intero
array.
Stream
Sorgente
Filtro
Oggetto
1
La classe sorgente
Il JAVA divide le possibili sorgenti dei flussi in alcune
classi:
1.
2.
3.
4.
5.
6.
ByteArrayInputStream: Può essere letta come array di
byte
StringBufferInputStream: È possibile leggere la stringa
corrispondente ai byte ricevuti
FileInputStream: Può essere letta come sequenza di byte
da un file
PipedInputStream: Viene utilizzato per leggere sequenze
di byte che provengono da un altro thread
SequenceInputStream: Permette di leggere due stream in
sequenza
Altre sorgenti: Come per esempio i socket, ecc.
2
Il classe filtro
Il JAVA mette a disposizione una serie di classi che
aggiungono funzionalità alla classe della sorgente:
1.
DataInputStream: Viene utilizzata per leggere dati
primitivi come int, float, double, ecc.
2.
BufferedInputStream: Previene la continua lettura dello
stream fisico, implementando un buffer tampone
3.
LineNumberInputStream: Tiene traccia del numero di
linee che è stato letto dallo stream
4.
PushbackInputStream: Mantiene un buffer di un byte, in
modo tale da permettere il “push back” di byte letti
3
Esempio
import java.io.*;
public static void main(String[] args) {
try {
DataInputStream file = new DataInputStream(
new BufferedInputStream(
new FileInputStream(“p.txt”)));
try {
String s;
while ((s = file.readLine()) != null) {
System.out.println("# " + s);
}
}
finally {
file.close();
}
}
catch (IOException e) {
System.out.println(“Errore di apertura");
}
}
4
I/O su file
Le classi per la gestione dei file sono principalmente
due:
1.
La classe File
Questa classe rappresenta un concetto molto ampio di file-system, in
quanto questa classe può non indicare un solo singolo file, ma anche
una directory intera, oppure un gruppo di file indicati con una stringa
filtro. Con questa classe si possono ottenere tutte le informazioni utili
all’accesso dei file e delle directory.
Con una stringa filtro si
identifica un gruppo di file
list() restituisce un
array di stringhe
contenente i nomi dei file
:
File path = new File(“.”);
String[] list = path.list();
:
5
I/O su file
:
File f1 = new File(“prova.txt”);
File f2 = new File(“prova.old”);
f1.renameTo(f2);
:
Permette di rinominare un file
:
File f1 = new File(“c:/documenti/prova”);
f1.mkdir();
f1.mkdirs();
:
Permette di creare interi alberi
di directory
6
I/O su file
2.
RandomAccessFile
Questa classe rappresenta l’insieme di record (delle stesse dimensioni)
all’interno di un file. Con essa è possibile posizionarsi su un preciso
record, utilizzando il metodo seek().
RandomAccessFile è una classe completamente separata dagli stream,
anche se i metodi in comune sono molti.
3.
StreamTokenizer
Questa classe permette di scomporre in token uno InputStream,
facilitando, per esempio, l’analisi sintattica di file aventi una
determinata grammatica.
7
JAVA - I/O System
Con il rilascio delle nuova versione di JAVA sono
state effettuate alcune modifiche sulla gestione degli
stream. Sono state introdotte due nuove classi
antenate: Reader e Writer.
Queste classi introducono funzionalità per la lettura e
la scrittura dei caratteri, nonché funzionalità di
lettura e scrittura Unicode.
Inoltre sono state introdotte classi che permettono la
gestione di file zip, gzip e file jar.
8
Serializzazione di Java
• Utilizzata da Java Remote Method Invocation per poter
passare oggetti e valori di dati primitivi come parametri e
risultato di invocazione di metodi
• Si usa il meccanismo delle interface Java
– se una classe può essere serializzata allora deve implementare la
interface Serializable che non contiene alcun metodo (marker
interface)
• Importante: si assume che chi deserializza un oggetto non
ha informazioni a priori:
• né sulla classe di cui l’oggetto è istanza
• né sulle classi di cui sono istanza i campi dell’oggetto
– ma deve avere accesso alle definizioni delle classi (file .class)
9
Struttura della serializzazione di Java
• La serializzazione di un oggetto riguarda:
– nome della classe, versione, numero, tipi e nomi delle
variabili istanza
– valori delle variabili istanza
• Può contenere anche dei riferimenti ad altri
oggetti:
– quando un oggetto viene serializzato, tutti gli oggetti a
cui fa riferimento sono ricorsivamente (depth-first)
serializzati con lui
– i riferimenti vengono trasformati in handles (riferimenti
all’interno della forma serializzata)
• handle per la definizione della classe (per poterla riusare)
• handle per i valori degli oggetti istanza delle classi (per poterli
riferire)
10
Il problema degli handle (1)
• Variabili istanza diverse che fanno riferimento allo stesso
oggetto devono usare lo stesso handle
• Esempio:
– Manager ha una variabile che contiene il riferimento di un
Employee che svolge compiti di segreteria per il Manager
– supponiamo di avere array staff di 3 Employee con i seguenti
valori:
11
Il problema degli handle (2)
• Se non si usassero gli handle
– quando si deserializza staff, ogni volta che si incontra il riferimento
a Harry si ricreerebbe un “nuovo” oggetto
12
L’uso della reflection nella serializzazione
• Java utilizza la riflessione per la serializzazione
– permettendo, una volta ottenuto il nome della classe ed
il tipo dei parametri da passare al costruttore
• Nella serializzazione:
– si trova il nome della classe dell’oggetto da serializzare
– si trovano nome, tipo e valori delle variabili istanza
• Nella deserializzazione:
– il nome delle classe viene usato per creare la classe
– si crea il nuovo costruttore con tipo dei parametri
corrispondenti a quelli specificati nella forma
serializzata
– si usano i valori letti dalla serializzazione come
parametri per il costruttore
13
Commenti sulla serializzazione
• Perché non tutte le classi sono serializzabili?
– sicurezza: un oggetto istanza di una classe puo’ essere scritto in file
e “letto”… compreso i dati privati!!
– istanze serializzate possono essere alterate e creare situazioni di
errori quando la JVM ricarica l’oggetto
• Per i campi da non serializzare si inserisce la parola chiave
transient davanti alla dichiarazione del campo:
– descrittori di file, descrittori di finestre etc.
• dipendenti dalla specifica macchina ed inutili da serializzare
– campi di cui si vuole mantenere la privatezza assoluta
• Esistono altre soluzioni
– interface Externalizable che permette di personalizzare il formato di
serializzazione (ad es. per crittografare i dati)
14
Esempio deserializzazione
public class CitiesNetwork implements Serializable {
private static CitiesNetwork me;
……
static public CitiesNetwork getInstance() {
FileInputStream f;
if (me == null){
String currentDirectory=System.getProperty("user.dir");
File storeDir = new File (currentDirectory+"/store");
if (!storeDir.exists()) storeDir.mkdir();
try {
f = new FileInputStream
(currentDirectory+"/store/CitiesNetwork.obj");
ObjectInputStream ois = new ObjectInputStream (f);
me = (CitiesNetwork) ois.readObject();
} catch (FileNotFoundException e) {
me = new CitiesNetwork();
} catch (IOException e) { e.printStackTrace();
} catch (ClassNotFoundException e) { e.printStackTrace();}
}
return me;
15
}
Esempio serializzazione
public void store(){
String currentDirectory =
System.getProperty("user.dir");
FileOutputStream f;
try {
f = new FileOutputStream
(currentDirectory+"/store/CitiesNetwork.obj");
ObjectOutputStream oos = new ObjectOutputStream(f);
oos.writeObject(this);
} catch (FileNotFoundException e) {
me = new CitiesNetwork();
} catch (IOException e) {
e.printStackTrace();
}
}
16