![]() ![]() |
|
![]() ![]() |
Abbiamo visto che Java fornisce classi per accedere a dati memorizzati in un file in formato
Più in generale, Java fornisce nel package java.io [locale,
Medialab,
Sun]
classi e metodi per scrivere e leggere dati che possono
risiedere ovunque: in un file, su disco, da qualche parte
nella rete, in memoria, o in un altro programma.
Per leggere dati da una sorgente, un programma "apre
uno stream" (cioè una sequenza di dati)
associata alla sorgente, e legge in modo sequenziale i dati:
![]() Analogamente, un programma può inviare dati ad una destinazione esterna aprendo uno stream associato ad essa, e scrivendoci i dati in modo sequenziale:
![]()
|
![]() ![]() |
|
![]() ![]() |
Le seguenti classi definiscono
stream di varia natura, fornendo le primitive read() e write() per leggere o
scrivere caratteri o byte.
|
![]() ![]() |
|
![]() ![]() |
Java fornisce molte altre classi
che consentono un accesso più ad alto livello a
dati esterni. Ne abbiamo già viste alcune per
scrivere e leggere dati strutturati da file.
Queste classi vengono usate come wrapper di
stream basici, e forniscono le funzionalità
aggiuntive in modo indipendente dal tipo di stream basico
cui vengono associate. Tuttavia sono diverse per stream di caratteri
o di byte.
|
![]() ![]() |
|
![]() ![]() |
Le classi ObjectInputStream e ObjectOutputStream definiscono
streams (basati su streams di byte) su cui si possono leggere e
scrivere oggetti.
La scrittura e la lettura di oggetti va sotto il nome di object serialization, poiché si basa sulla possibilità di scrivere lo stato di un oggetto in una forma sequenziale, sufficiente per ricostruire l'oggetto quando viene riletto. La serializzazione di oggetti viene usata principalmente in due modi:
Per utilizzare correttamente questo meccanismo occorre sapere:
|
![]() ![]() |
|
![]() ![]() |
Il seguente esempio mostra come si scrivono alcuni oggetti su di un ObjectOutputStream che incapsula
il file (binario) theTime.
L'oggetto new Date()
rappresenta la data corrente (con precisione in millisecondi).
Se si scrive in un ObjectOutputStream con il metodo writeObject un oggetto che ha puntatori ad altri oggetti, allora tutti gli oggetti raggiungibili, sia direttamente che transitivamente, vengono scritti nello stream, in modo da mantenere le relazioni tra di essi. Il metodo writeObject lancia un'eccezione NotSerializableException se cerca di serializzare un oggetto che non implementa l'interfaccia Serializable. Per leggere degli oggetti da uno stream, si usa in modo simmetrico la classe ObjectInputStream. Il prossimo esempio legge dal file chiamato theTime gli oggetti che erano stati scritti dal programma WriteValues:
Naturalmente gli oggetti devono essere riletti nell'ordine in cui erano stati scritti. Si noti che il tipo di readObject è Object e quindi serve un cast. Il metodo può lanciare l'eccezione controllata ClassNotFoundException.
|
![]() ![]() |
|
![]() ![]() |
Un oggetto è serializzabile solo se la sua classe implementa
l'interfaccia Serializable.
Quindi se si vuole che le istanze di una classe che state scrivendo
siano serializzabili, è sufficiente dichiarare che la classe
implementa Serializable.
Poiché questa intefaccia non ha metodi, non occorre fare altro.
La serializzazione delle istanze di una classe viene gestita dal metodo defaultWriteObject della classe ObjectOutputStream. Questo metodo scrive automaticamente tutto ciò che è richiesto per ricostruire le istanze di una classe, e cioè
Per molte classi questo comportamento è soddisfacente. A volte, tuttavia, il programmatore può volere un maggior controllo su questo meccanismo. Si può personalizzare la serializzazione per proprie classi fornendo due metodi d'istanza: writeObject e readObject. Si rimanda alla documentazione di Java per ulteriori dettagli.
Per concludere, si osservi che la serializzazione di oggetti di una classe può causare problemi di sicurezza, poiché informazioni private o sensibili possono essere accedute da altri. Per evitare ciò ci sono due modi semplici:
|