Home

Binary Serialization

 

Object Serialization and De-Serialization

 
 

Introduction

Consider the following program:

Serialization

Imports System.IO

Public Class Exercise

    Private Sub btnWrite_Click(ByVal sender As System.Object, _
                               ByVal e As System.EventArgs) Handles btnWrite.Click
        Dim Make As String = txtMake.Text
        Dim Model As String = txtModel.Text
        Dim Year As Integer = CInt(txtYear.Text)
        Dim CarColor As Integer = cbxColors.SelectedIndex

        Dim stmCar As FileStream = New FileStream("Car1.car", FileMode.Create)
        Dim bnwCar As BinaryWriter = New BinaryWriter(stmCar)

        Try
            bnwCar.Write(Make)
            bnwCar.Write(Model)
            bnwCar.Write(Year)
            bnwCar.Write(CarColor)
        Finally
            bnwCar.Close()
            stmCar.Close()
        End Try
    End Sub
End Class

Here is an example of running the program:

This is an example of the techniques used in file processing to save individual data of primitive types:

Saving the variables in a method

The values can be retrieved with the following code:

Imports System.IO

Public Class Exercise

    Private Sub btnWrite_Click(ByVal sender As System.Object, _
                               ByVal e As System.EventArgs) Handles btnWrite.Click
        Dim Make As String = txtMake.Text
        Dim Model As String = txtModel.Text
        Dim Year As Integer = CInt(txtYear.Text)
        Dim CarColor As Integer = cbxColors.SelectedIndex

        Dim stmCar As FileStream = New FileStream("Car1.car", FileMode.Create)
        Dim bnwCar As BinaryWriter = New BinaryWriter(stmCar)

        Try
            bnwCar.Write(Make)
            bnwCar.Write(Model)
            bnwCar.Write(Year)
            bnwCar.Write(CarColor)
        Finally
            bnwCar.Close()
            stmCar.Close()
        End Try
    End Sub

    Private Sub btnRead_Click(ByVal sender As Object, _
                              ByVal e As System.EventArgs) Handles btnRead.Click
        Dim stmCar As FileStream = New FileStream("Car1.car", FileMode.Open)
        Dim bnrCar As BinaryReader = New BinaryReader(stmCar)

        Try
            txtMake.Text = bnrCar.ReadString()
            txtModel.Text = bnrCar.ReadString()
            txtYear.Text = bnrCar.ReadUInt32().ToString()
            cbxColors.SelectedIndex = bnrCar.ReadInt32()
        Finally
            bnrCar.Close()
            stmCar.Close()
        End Try
    End Sub
End Class

In the same way, you can save the individual fields of a class or you can retrieve the individual fields of a car:

Saving the individual parts of an object

Here is an example:

Class: Car.vb
Public Class Car
    Public Make As String
    Public Model As String
    Public Year As Integer
    Public Color As Integer
End Class
Imports System.IO

Public Class Exercise

    Private Sub btnWrite_Click(ByVal sender As System.Object, _
                               ByVal e As System.EventArgs) Handles btnWrite.Click
        Dim Vehicle As Car = New Car()

        Vehicle.Make = txtMake.Text
        Vehicle.Model = txtModel.Text
        Vehicle.Year = CInt(txtYear.Text)
        Vehicle.Color = cbxColors.SelectedIndex

        Dim stmCar As FileStream = New FileStream("Car2.car", FileMode.Create)
        Dim bnwCar As BinaryWriter = New BinaryWriter(stmCar)

        Try
            bnwCar.Write(Vehicle.Make)
            bnwCar.Write(Vehicle.Model)
            bnwCar.Write(Vehicle.Year)
            bnwCar.Write(Vehicle.Color)
        Finally
            bnwCar.Close()
            stmCar.Close()
        End Try
    End Sub

    Private Sub btnRead_Click(ByVal sender As Object, _
                              ByVal e As System.EventArgs) Handles btnRead.Click
        Dim stmCar As FileStream = New FileStream("Car2.car", FileMode.Open)
        Dim bnrCar As BinaryReader = New BinaryReader(stmCar)

        Try
            Dim Vehicle As Car = New Car()

            Vehicle.Make = bnrCar.ReadString()
            Vehicle.Model = bnrCar.ReadString()
            Vehicle.Year = bnrCar.ReadUInt32()
            Vehicle.Color = bnrCar.ReadInt32()

            txtMake.Text = Vehicle.Make
            txtModel.Text = Vehicle.Model
            txtYear.Text = Vehicle.Year
            cbxColors.SelectedIndex = Vehicle.Color
        Finally
            bnrCar.Close()
            stmCar.Close()
        End Try
    End Sub
End Class

When it comes to a class, the problem with saving individual fields is that you could forget to save one of the fields. For example, considering a Car class, if you don't save the Make information of a Car object and retrieve or open the saved object on another computer, the receiving user would miss some information and the car cannot be completely identifiable. An alternative is to save the whole Car object.

Object serialization consists of saving a whole object as one instead of its individual fields:

Serialization

In other words, a variable declared from a class can be saved to a stream and then the saved object can be retrieved later or on another computer. The .NET Framework supports two types of object serialization: binary and SOAP.

Practical Learning: Introducing Serialization

  1. Start Microsoft Visual Basic and create a Windows Forms Application named RealEstate1
  2. To create a new form, on the main menu, click Projects -> Add Windows Form...
  3. Set the Name to PropertyEditor and click Add
  4. Design the form as follows:
     
    Real Estate
    Control Text Name Other Properties
    Label Label Property #:    
    TextBox TextBox   txtPropertyNumber Modifiers: Public
    Label Label Property Type:    
    ComboBox ComboBox   cbxPropertyTypes Modifiers: Public
    Items:
    Unknown
    Single Family
    Townhouse
    Condominium
    Label Label Address:    
    TextBox TextBox   txtAddress Modifiers: Public
    Label Label City:    
    TextBox TextBox   txtCity Modifiers: Public
    Label Label State:    
    ComboBox TextBox   cbxStates Modifiers: Public
    Items:
    DC
    MD
    PA
    VA
    WV
    Label Label ZIP Code:    
    TextBox TextBox   txtZIPCode Modifiers: Public
    Label Label Bedrooms:    
    TextBox TextBox 0 txtBedrooms Modifiers: Public
    Label Label Bathrooms:    
    TextBox TextBox 1.0 txtBathrooms Modifiers: Public
    Label Label Market Value:    
    TextBox TextBox 0.00 txtMarketValue Modifiers: Public
    Button Button OK btnOK DialogResult: OK
    Button Button Cancel btnCancel DialogResult: Cancel
    Form
    FormBorderStyle: FixedDialog
    Text: Altair Realtors - Property Editor
    StartPosition: CenterScreen
    AcceptButton: btnOK
    CancelButton: btnCancel
    MaximizeBox: False
    MinimizeBox: False
    ShowInTaskBar: False
  5. In the Solution Explorer, right-click Form1.vb and click Rename
  6. Type RealEstate.vb and press Enter twice (to display that form)
  7. Design the form as follows:
     
    Altair Realtors
    Control Text Name
    Label Label Property #:  
    TextBox TextBox   txtPropertyNumber
    Button Open btnOpen
    Label Label Property Type:  
    TextBox TextBox   txtPropertyType
    Label Label Address:  
    TextBox TextBox   txtAddress
    Label Label City:  
    TextBox TextBox   txtCity
    Label Label State:  
    TextBox TextBox   txtState
    Label Label ZIP Code:  
    TextBox TextBox   txtZIPCode
    Label Label Bedrooms:  
    TextBox TextBox 0 txtBedrooms
    Label Label Bathrooms:  
    TextBox TextBox 1.0 txtBathrooms
    Label Label Market Value:  
    TextBox TextBox 0.00 txtMarketValue
    Button Button &New Property... btnNewProperty
    Button Button Close btnClose
    Form
    FormBorderStyle: FixedDialog
    Text: Altair Realtors - Property Editor
    StartPosition: CenterScreen
  8. Save the form

Binary Serialization

Binary serialization works by processing an object rather than streaming its individual member variables. This means that, to use it, you define an object and initialize it, or "fill" it, with the necessary values and any information you judge necessary. This creates a "state" of the object. It is this state that you prepare to serialize. When you save the object, it is converted into a stream.

To perform binary serialization, there are a few steps you must follow. When creating the class whose objects would be serialized, start it with the <Serializable> attribute. Here is an example:

<Serializable()> Public Class Car
    Public Make As String
    Public Model As String
    Public Year As Integer
    Public Color As Integer
End Class

Before serializing an object, you should reference the System.Runtime.Serialization.Formatters.Binary namespace. The class responsible for binary serialization is called BinaryFormatter. This class is equipped with two constructors. The default constructor is used to simply create an object.

After declaring the variable, to actually serialize an object, call the Serialize() method of the BinaryFormatter class. The method is overloaded with two versions. One of the versions of this method uses the following syntax:

Public Sub Serialize ( _
	serializationStream As Stream, _
	graph As Object _
)

The first argument to this method must be an object of a Stream-based class, such as a FileStream object. The second argument must be the object to serialize. This means that, before calling this method, you should have built the object.

Here is an example:

Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary

Public Class Exercise

    Private Sub btnWrite_Click(ByVal sender As System.Object, _
                               ByVal e As System.EventArgs) Handles btnWrite.Click
        Dim vehicle As Car = New Car()
        vehicle.Make = txtMake.Text
        vehicle.Model = txtModel.Text
        vehicle.Year = CInt(txtYear.Text)
        vehicle.Color = cbxColors.SelectedIndex

        Dim stmCar As FileStream = New FileStream("Car3.car", FileMode.Create)
        Dim bfmCar As BinaryFormatter = New BinaryFormatter()

        bfmCar.Serialize(stmCar, vehicle)
    End Sub
End Class

Practical Learning: Serializing an Object

  1. To create a new class, on the main menu, click Project -> Add Class...
  2. Set the Name to SampleProperty and click Add
  3. Change the file as follows:
     
    <Serializable()> Public Class SampleProperty
        Public PropertyNumber As String
        Public PropertyType As String
        Public Address As String
        Public City As String
        Public State As String
        Public ZIPCode As Integer
        Public Bedrooms As Short
        Public Bathrooms As Single
        Public MarketValue As Double
    End Class
  4. In the Solution Explorer, right-click RealEstate.vb and click View Code
  5. In the Class Name combo box, select (RealEstate Events)
  6. In the Method Name combo box, select Click and change the file as follows:
     
    Imports System.IO
    Imports System.Runtime.Serialization.Formatters.Binary
    
    Public Class RealEstate
    
        Private Sub btnNewProperty_Click(ByVal sender As System.Object, _
                                         ByVal e As System.EventArgs) _
    				     Handles btnNewProperty.Click
            Dim Editor As PropertyEditor = New PropertyEditor
            Dim DirInfo As DirectoryInfo = _
                      Directory.CreateDirectory("C:\Altair Realtors\Properties")
    
            Dim RndNumber As Random = New Random
            Dim LeftNumber As Integer = RndNumber.Next(100, 999)
            Dim RightNumber As Integer = RndNumber.Next(100, 999)
            Editor.txtPropertyNumber.Text = LeftNumber.ToString() & "-" _
                                        & RightNumber.ToString()
    
            If Editor.ShowDialog() = DialogResult.OK Then
                Dim Prop As SampleProperty = New SampleProperty
                prop.PropertyNumber = Editor.txtPropertyNumber.Text
                prop.PropertyType = Editor.cbxPropertyTypes.Text
                prop.Address = Editor.txtAddress.Text
                prop.City = Editor.txtCity.Text
                prop.State = Editor.cbxStates.Text
                prop.ZIPCode = CInt(Editor.txtZIPCode.Text)
                prop.Bedrooms = CInt(Editor.txtBedrooms.Text)
                prop.Bathrooms = CSng(Editor.txtBathrooms.Text)
                prop.MarketValue = CDbl(Editor.txtMarketValue.Text)
    
                Dim strFilename As String = DirInfo.FullName & "\" & _
                            Editor.txtPropertyNumber.Text & ".prp"
                Dim stmProperty As FileStream = New FileStream(strFilename, _
                                 FileMode.Create, FileAccess.Write)
                Dim bfmProperty As BinaryFormatter = New BinaryFormatter
    
                bfmProperty.Serialize(stmProperty, prop)
            End If
        End Sub
    End Class
  7. In the Class Name combo box, select btnClose
  8. In the Method name combo box, select Click and implement the event as follows:
     
    Private Sub btnClose_Click(ByVal sender As Object, _
                               ByVal e As System.EventArgs) _
                               Handles btnClose.Click
            End
    End Sub
  9. Execute the application and continuously click the New Property button to create the following properties (let the computer specify the property number):
     
     
    Property Type  Address  City State  ZIP Code Beds Baths Market Value
    Single Family 11604 Aldora Avenue Baltimore MD 21205 5 3.5 325650
    Townhouse 495 Parker House Terrace Gettysburg WV 26201 3 2.5 225500
    Condominium 5900 24th Street NW #812 Washington DC 20008 1 1.0 388665
    Single Family 6114 Costinha Avenue Martinsburg WV 25401 4 3.5 325000
    Condominium 10710 Desprello Street #10D Rockville MD 20856 1 1.0 528445
  10. Close the form and return to your programming environment

De-Serialization

As serialization is the process of storing an object to a medium, the opposite, de-serialization is used to retrieve an object from a stream. To support this, the BinaryFormatter class is equipped with the Deserialize() method. Like Serialize(), the Deserialize() method is overloaded with two versions. One of them uses the following syntax:

Public Function Deserialize ( _
	serializationStream As Stream _
) As Object

This method takes as argument a Stream-based object, such as a FileStream variable, that indicates where the file is located. The Deserialize() method returns an Object object. As a goal, you want the Deserialize() method to produce the type of object that was saved so you can retrieve the values that the returned object holds. Because the method returns an Object value, you must cast the returned value to the type of your class.

Once the Deserialize() method has returned the desired object, you can access its values. Here is an example:

Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary

Public Class Exercise

    Private Sub btnWrite_Click(ByVal sender As System.Object, _
                               ByVal e As System.EventArgs) Handles btnWrite.Click
        Dim Vehicle As Car = New Car()

        Vehicle.Make = txtMake.Text
        Vehicle.Model = txtModel.Text
        Vehicle.Year = CInt(txtYear.Text)
        Vehicle.Color = cbxColors.SelectedIndex

        Dim stmCar As FileStream = New FileStream("Car3.car", FileMode.Create)
        Dim bfmCar As BinaryFormatter = New BinaryFormatter()

        bfmCar.Serialize(stmCar, vehicle)
    End Sub

    Private Sub btnRead_Click(ByVal sender As Object, _
                              ByVal e As System.EventArgs) Handles btnRead.Click
        Dim stmCar As FileStream = New FileStream("Car3.car", FileMode.Open)
        Dim bnrCar As BinaryReader = New BinaryReader(stmCar)

        Dim bfmCar As BinaryFormatter = New BinaryFormatter()
        Dim Vehicle As Car = CType(bfmCar.Deserialize(stmCar), Car)

        txtMake.Text = Vehicle.Make
        txtModel.Text = Vehicle.Model
        txtYear.Text = Vehicle.Year.ToString()
        cbxColors.SelectedIndex = Vehicle.Color
    End Sub
End Class

Practical Learning: De-Serializing an Object

  1. In the Class Name combo box, select btnOpen
  2. In the Method name combo box, select Click and implement the event as follows:
     
    Private Sub btnOpen_Click(ByVal sender As Object, _
                                  ByVal e As System.EventArgs) _
                                  Handles btnOpen.Click
            Dim DirProperties As DirectoryInfo = _
              New DirectoryInfo("C:\Altair Realtors\Properties")
            Dim FleProperties() As FileInfo = DirProperties.GetFiles()
    
            If DirProperties.Exists = True Then
                Dim Found As Boolean = False
                Dim Prop As SampleProperty = Nothing
                Dim fle As FileInfo
                For Each fle In FleProperties
                    Dim stmProperty As FileStream = _
    			New FileStream(fle.FullName, _
                                           FileMode.Open, _
                     FileAccess.Read)
                    Dim bfmProperty As BinaryFormatter = New BinaryFormatter()
                    Prop = CType(bfmProperty.Deserialize(stmProperty), _
    				SampleProperty)
    
                    If Prop.PropertyNumber = txtPropertyNumber.Text Then
                        Found = True
                    End If
                Next
    
                If Found = True Then
                    txtPropertyType.Text = Prop.PropertyType
                    txtAddress.Text = Prop.Address
                    txtCity.Text = Prop.City
                    txtState.Text = Prop.State
                    txtZIPCode.Text = Prop.ZIPCode
                    txtBedrooms.Text = Prop.Bedrooms
                    txtBathrooms.Text = FormatNumber(Prop.Bathrooms)
                    txtMarketValue.Text = FormatNumber(Prop.MarketValue)
                Else
                    MsgBox("There is no property with " & _
               "that number in our database")
    
                    txtPropertyType.Text = "Unknown"
                    txtAddress.Text = ""
                    txtCity.Text = ""
                    txtState.Text = ""
                    txtZIPCode.Text = "00000"
                    txtBedrooms.Text = "0"
                    txtBathrooms.Text = "0.00"
                    txtMarketValue.Text = "0.00"
                End If
            End If
    End Sub
  3. Execute the application and try opening a previously save property using its number
  4. Close the form and return to your programming environment

Details on Serialization

 

Partial Serialization

In the examples we have used so far, we were saving the whole object. You can make it possible to save only some parts of the class. When creating a class, you can specify what fields would be serialized and which ones would not be. To specify that a member cannot be saved, you can mark it with the <NonSerialized()> attribute. Here is an example:

<Serializable()> Public Class Car1
    Public Make As String
    Public Model As String

    ' Because the value of a car can change,
    ' there is no reason to save it
    <NonSerialized()> _
    Public Value As Double
    Public Year As Integer
    Public Color As Integer
End Class

After creating the class, you can declare a variable of it and serialize it, using either the binary or the SOAP approach. You can then retrieve the object and its values, using any of the techniques we learned earlier.

Implementing a Custom Serialized Class

To support serialization, the .NET Framework provides the ISerializable interface. You can create a class that implements this interface to customize the serialization process. Even if you plan to use this interface, the class you create must be marked with the <Serializable> attribute.

.NET Built-In Serialized Classes

The .NET Framework is filled with many classes ready for serialization. To know that a class is ready for serialization, when viewing its documentation either in the MSDN web site or in the help documentation, check that it is marked with the [SerializableAttribute]. Here is an example of such as class:

The Serializable attribute of a built-in class

Some of these classes provide the properties and methods to create an object and directly save it. For some other classes, you must first create a class, mark it with the <Serializable> attribute, build an object of it, and then pass it to the .NET class.

 


Home Copyright © 2008-2012 FunctionX