File binari in Java e serializzazione

Dopo aver visto come leggere e scrivere byte singoli e a blocchi in un file binario (link), in quest’articolo vediamo un altro modo di operare con i file binari che dà la possibilità di leggere e scrivere direttamente variabili primitive e, addirittura, oggetti. Questa modalità di accesso ad un file binario, sfrutta la cosiddetta serializzazione che è una particolare funzionalità di Java che permette di tradurre le variabili e gli oggetti in uno stream di byte che può essere salvato in maniera persistente in un file binario. Questo stream di byte successivamente può essere riletto e trasformato attraverso un operazione inversa di de-serializzazione, per ottenere le variabili e gli oggetti originari.

Lettura e scrittura binaria di variabili primitive e oggetti

Ciò può essere realizzato utilizzando gli oggetti di classe ObjectOutputStream e ObjectInputStream del package java.io, istanziati a partire da oggetti delle classi FileOutputStream FileInputStream già viste in un altro articolo sui file binari a cui si rimanda: link. Sintassi:

Le classi ObjectOutputStream e ObjectInputStream dispongono di metodi nella forma writeTipoDato e readTipoDato, rispettivamente, dove TipoDato può essere sostituito con  Byte, Char, Int, Double, Object, ecc.. a seconda del tipo di dato che si deve scrivere/leggere, compreso un oggetto di un qualunque tipo di classe. In quest’ultimo caso però bisogna ricordarsi che la classe dell’oggetto deve necessariamente implementare l’interfaccia Serializable.

Vediamo un semplice esempio che utilizza la serializzazione e la de-serializzazione per scrivere e leggere un oggetto in un file binario.

La classe di test precedente utilizza la classe Voto seguente:

e la classe Aunno seguente:

L’esecuzione del programma produce il file binario alunno.dat, che ovviamente non sarà leggibile con un semplice editor di testi. Esso, inoltre, viene letto tramite il processo inverso di de-serializzazione per produrre il file di testo alunno.txt con quanto letto e visualizzare il seguente output sulla console, in modo da testare il corretto funzionamento del codice scritto:

scrivereOggetti

Il codice per le parti di serializzazione e de-serializzazione è commentato, per il resto è autoesplicativo. Si fa notare solo che entrambe le classi, Voto e Alunno, implementano l’interfaccia Serializable (righe evidenziate in giallo) affinché possano essere serializzate.

P.S. Per quanto riguarda le eccezioni che vengono propagate dalla classe di test con la clausola throws, si fa osservare che:

  • ParseException, è legata alla conversione dell’oggetto di classe Date in stringa, che avviene attraverso il metodo parse() dell’oggetto di classe DateFormat nella classe Voto. (Per approfondimenti sulla classe Date si rimanda al seguente articolo: link).
  • FileNotFoundException, deriva dall’oggetto FileInputStream ed è legata agli errori potenziali durante l’apertura del file.
  • IOException, è legata a tutti gli errori potenziali durante le operazioni di lettura e scrittura dei file.
  • ClassNotFoundException, deriva da altri problemi potenziali legati alla serializzazione che per brevità non vengono qui menzionati.

Un piccola precisazione, queste eccezioni piuttosto che essere propagate, così come è stato fatto nell’esempio di sopra nel main, andrebbero gestite. Per brevità e semplicità di trattazione non è stato fatto. Troppe cose da ricordare? Non preoccupatevi, gli attuali IDE come Netbeans o Eclipse ci aiutano con utilissimi suggerimenti.