Binary Formatter


Livello: Principiante/Intermedio


Tra poco vedremo come utilizzare la Classe BinaryFormatter per Serializzare un oggetto in formato Binario. Le possibilità d'implementazione sono varie, io la utilizzerò per creare una gestione dei settaggi personalizzata che prevede, oltre il semplice salvataggio di alcuni valori, anche la possibilità di Criptare i dati salvati.(in questo modo si evita che l'utilizzatore possa curiosare all'interno dei valori salvati)

nb: il metodo di Criptaggio/Decriptaggio utilizzato in questo esempio, è molto grossolano e solo per scopo dimostrativo, non affidatevi a tale sistema per la protezione dei vostri dati.

Visto che è possibile Serializzare un solo oggetto alla volta, per poter Serializzare 2 o più valori, utilizzerò una Classe (Serializzabile) al cui interno inserirò i dati che intendo salvare.

Definiamo la Classe contenitore:

codice:
<System.Serializable()> _
Public Class MySettings
 
EndClass
L'attributo <System.Serializable()> indica che la Classe può essere serializzata, però prestate attenzione perchè al suo interno potranno essere inseriti solamente altri oggetti che siano anch'essi serializzabili (nel caso vogliate inserire altre Classi personali al suo interno) ed in più, le Classi derivate direttamente da questa, non erediteranno la posibilità di essere Serializzate, ma andrà specificato manualmente l'attributo su ogni Classe ereditata.

Adesso inseriamo 2 valori di cui vogliamo tener traccia durante l'utilizzo della nostra applicazione, per rendere l'esempio meno complesso possibile, utilizzerò solo 2 valori:

1- La posizione del file contenente i settaggi
2 - La posizione (coordinate) del Form.

Aggiungiamo, quindi, 2 proprietà alla nostra Classe:
codice:
<System.Serializable()> _
Public Class MySettings
 
'-- variabili contenenti i valori di default preconfigurati
Private pPathFile AsString = Application.StartupPath & "\Settings.dat"
Private pAppPosition As Point = New Point(300, 250)
 
Public Property PathFile() As String
Get
Return pPathFile
End Get
Set(ByVal value As String)
pPathFile = value
End Set
End Property
 
Public Property AppPosition() As Point
Get
Return pAppPosition
End Get
Set(ByVal value As Point)
pAppPosition = value
End Set
End Property
 
End Class

Bene, abbiamo la nostra Classe Serializzabile con all'intero 2 Proprietà che verranno salvate e che potremo riutilizzare durante l'utilizzo dell'applicazione.
Adesso, però, ci servono i Metodi per caricare e salvare i nostri dati.

Iniziamo col vedere il Metodo di salvataggio, così sarà più semplice intuire quello di caricamento.
La funzione eseguirà le seguenti operazioni:
Creerà in memoria un oggetto serializzato - attraverso l'utilizzo della Classe BinaryFormatter - cripterà il contenuto e lo salverà su file. (i dettagli li trovate direttamente come commento al codice)
codice:
Public Function SaveSettings() As Boolean
Try
  '-- creo il flusso di memorizzazione in memoria
  Using ms As New MemoryStream
     '-- creo il formattatore
     Dim formatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
     '-- Serializzo l'oggetto in memoria
     formatter.Serialize(ms, Me)
     '-- recupero l'oggetto serializzato sottoforma di bytes
     Dim buf As Byte() = ms.ToArray
     '-- cripto i bytes
     CryptDecrypt(buf)
     '-- salvo su file il buffer criptato
     Using fs As New FileStream(PathFile, FileMode.OpenOrCreate)
        fs.Write(buf, 0, buf.Length)
     End Using
  End Using

  Return True

Catch ex As Exception
  '-- visualizzo l'errore
  MessageBox.Show(ex.Message)
  Return False
End Try

End Function
La Routine atta a Criptare/Decriptare il flusso di bytes, è la seguente:
codice:
Private Sub CryptDecrypt(ByVal buf() As Byte)
  '-- effettuo uno XOR su ogni byte
  For i As Integer = 0 To buf.Length - 1
     buf(i) = CByte(buf(i) Xor 100)
  Next
End Sub
Il processo inverso (ovvero il caricamento dei dati dal file criptato salvato) eseguirà le seguenti operazioni:
Leggerà il contenuto del file, decripterà il flusso di bytes e successivamente deserializzerà l'oggetto dalla memoria (i dettagli li trovate direttamente come commento al codice)


codice:
Public Function LoadSettings() As Boolean
'-- verifico che il file esista
If File.Exists(PathFile) Then
 Try
 '-- creo il FileStream per la lettura del file
 Using fs As New FileStream(PathFile, FileMode.Open)
  '-- creo il buffer
  Dim buf(fs.Length - 1) As Byte
  '-- scrivo il contenuto del file all'interno del buffer
  fs.Read(buf, 0, fs.Length)
  '-- decripto il buffer
  CryptDecrypt(buf)
  '-- creo, in memoria, un flusso di archivio per il buffer decriptato
  Using ms As New MemoryStream(buf)
     '-- creo il formattatore
     Dim Formatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
     '-- deserializzo l'oggetto dalla memoria
     Dim Settings As MySettings = CType(Formatter.Deserialize(ms), MySettings)
     '-- Setto i valori correnti con i valori deserializzati
     Me.PathFile = Settings.PathFile
     Me.AppPosition = Settings.AppPosition
  End Using
 End Using

 
 Return True

 
 Catch ex As Exception
    '-- visualizzo l'errore
    MessageBox.Show(ex.Message)
    Return False
 End Try

Else
  '-- se non esiste, lo creo con le impostazioni preconfigurate
  Return Me.SaveSettings()
End If
 
End Function
Vediamo il codice da utilizzare nel Form principale, per richiamare/salvare il valore della Coordinata.

codice:
Public Class fMain
 
Private Settings As New MySettings
 
Public Sub New()
  ' Chiamata richiesta da Progettazione Windows Form.
  InitializeComponent()
  '-- richiamo la SUB del caricamento dati
  GetSettings()
End Sub

Private Sub GetSettings()
  '-- carico i settaggi dal file dat
  If Settings.LoadSettings() Then
     '-- imposto i dati
     Me.Location = Settings.AppPosition
  Else
     '-- gestisco l'eventuale mancato caricamento dei settaggi
     '-- ....
  End If
End Sub

Private Sub SaveSettings()
  '-- salvo le configurazioni su file
  Settings.AppPosition = Me.Location
  If Not Settings.SaveSettings() Then
     '-- gestisco l'eventuale mancato salvataggio dei settaggi
     '-- ....
  End If
End Sub

Private Sub fMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
  '-- richiamo la SUB del salvataggio dati
  SaveSettings()
End Sub
 
End Class
Conclusioni:
L'esempio vuole essere solo una piccola linea guida sulla possibilità di serializzare e criptare una Classe contenete diverse proprietà che potrebbero ritornare utili durante gli usi dell'applicativo, nulla vieta di inserire proprietà "Collection" o proprietà che puntano a Classi personalizzate (che espongono sempre l'attributo Serializable).

Alla prossima.