"A liberal education is at the heart of a civil society, and at the heart of a liberal education is the act of teaching." - A(ngelo) Bartlett Giamatti


Edit

Overview

From Wikipedia: Serialization is the process of saving an object onto a storage medium (such as a file, or a memory buffer) or to transmit it across a network connection link in binary form. The series of bytes or the format can be used to re-create an object that is identical in its internal state to the original object (actually, a clone).

In the .NET framwork, an object can be serialized into simple XML, SOAP or a Binary format.

The various classes you can use as serializers are:


An additional format known as JSON can be used with a 3rd party library. I've seen at least 2 open-source libraries that will do the same basic task with that format, but have not used either of them in a production app.

Edit

How to choose a formatter

As you will see below, this comes down to speed, human readability and compatibility with SOAP standards. You must decide which of these is most important to your application. If speed is the most important, use the BinaryFormatter; otherwise, use the XMLFormatter unless you absolutely must have compatibility with a SOAP standard.

Edit

Speed

Simple performance test (object with a 2 public fields serialized 10,000 times):

  • SoapFormatter - 1.76 seconds
  • XMLFormatter - 1.55 seconds
  • BinaryFormatter - 0.11 seconds

Second test on a small list of 1000 objects executed 1000 times:

  • SoapFormatter - n/a - This formatter is not compatible with Generics
  • XMLFormatter - 3.45 seconds
  • BinaryFormatter - 3.69 seconds

With individual objects, the BinaryFormatter is definitely faster than the other 2. With List objects, the performance difference is negligible.

Edit

Size of output

Using a simple class with 2 numeric fields:

  • SoapFormatter - 683 bytes
  • XMLFormatter - 203 bytes
  • BinaryFormatter - 161 bytes

Edit

Human Readability

The BinaryFormatter is not really human readable, so if that's a requirement, don't choose that formatter.

XML output of a simple class with 2 numeric values:

<?xml version="1.0"?>
<MyTestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Num1>993929257</Num1>
  <Num2>701858102</Num2>
</MyTestClass>

The class in SOAP format:

<SOAP-ENV:Envelope 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
  xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" 
  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:MyTestClass id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/TestXmlSerializer/TestXmlSerializer%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<Num1>1583791413</Num1>
<Num2>656474251</Num2>
</a1:MyTestClass>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Edit

Sample Code

Edit

Instantiating the formatter

For the XMLSerializer, you'll need to specify the type of the object you'll be serializing in the constructor:

Dim ser As New System.Xml.Serialization.XmlSerializer(myObject.GetType)
Dim ser As New System.Xml.Serialization.XmlSerializer(GetType(MyClassName))
Dim ser As New System.Xml.Serialization.XmlSerializer(GetType(List(of MyClassName)))

For the other 2, a simple constructor call is sufficient:

Dim ser As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
Dim ser As New System.Runtime.Serialization.Formatters.Soap.SoapFormatter

Edit

Setting up your object

Each class you serialize must have the Serializable attribute. Each of the items in your class must also be defined with that attribute. In this case below, Integer (along with all of the primitive types) is already defined with that attribute.

<Serializable()> Public Class MyTestClass
    Public Num1 As Integer
    Public Num2 As Integer
End Class

Edit

Serializing an object to a file

Assuming the serializer has been instantiated already as ser.

Using fs As New IO.StreamWriter("c:\temp\myfilename.xml")
    ser.Serialize(fs, myObject)
End Using

Do not serialize more than one object to the same stream unless you've implemented a method of reading back in each individual chunk of data. The Deserialize method is unable to handle multiple objects in a single stream automatically.

You can serialize an entire List(of T) object into a stream and the deserializer will recreate the full List object in one call to Deserialize.

Edit

Deserializing an object from a file

Assuming the serializer has been instantiated already as ser.

Using fs As New IO.StreamReader("c:\temp\myfilename.xml")
    myObject = CType(ser.Deserialize(fs), MyTestClass)
End Using

Edit

Serializing an object to a byte array

Assuming the serializer has been instantiated already as ser.

Dim data() as Byte
Using fs As New IO.MemoryStream("c:\temp\myfilename.xml")
    ser.Serialize(fs, myObject)
    data = fs.ToArray
End Using

Edit

Serializing an object to a String

Assuming the serializer has been instantiated already as ser.

Dim result as String
Using fs As New IO.MemoryStream("c:\temp\myfilename.xml")
    ser.Serialize(fs, myObject)
    result = Text.Encoding.Default.GetString(fs.ToArray)
End Using

Edit

Controlling XML output

For the XMLFormatter, there are a variety of attributes that can be applied to your class that will generate and interpret different XML structures (for these examples, I'm going to remove the namespace attributes for readability):

Original class:

<Serializable()> Public Class MyTestClass
    Public Num1 As Integer
    Public Num2 As Integer
End Class

Resulting XML:

<?xml version="1.0"?>
<MyTestClass">
  <Num1>0</Num1>
  <Num2>0</Num2>
</MyTestClass>

Class with renamed element:

<Serializable()> Public Class MyTestClass
    <Xml.Serialization.XmlElement("MainNum")> Public Num1 As Integer
    Public Num2 As Integer
End Class

Resulting XML:

<?xml version="1.0"?>
<MyTestClass">
  <MainNum>0</MainNum>
  <Num2>0</Num2>
</MyTestClass>

Class with element mapped to an attribute instead:

<Serializable()> Public Class MyTestClass
    <Xml.Serialization.XmlAttribute()> Public Num1 As Integer
    <Xml.Serialization.XmlAttribute()> Public Num2 As Integer
End Class

<?xml version="1.0"?>
<MyTestClass Num1="0" Num2="0" />

Edit

Writing multiple objects to one file

This technique will work equally well with any of the serializer types, but since it writes the length of each block in binary, it's already lost it's "human readability". As such, the BinaryFormatter is used here because of it's speed. This block (without the Console.Writeline) ran in 0.25 seconds using the BinaryFormatter and 2.02 seconds using the XMLSerializer.

Dim ser As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

Dim fn As String = "c:\temp\myfilename.dat" IO.File.Delete(fn)

Using fs As IO.FileStream = IO.File.OpenWrite(fn) For i As Integer = 0 To 9999 Dim tmp As New MyTestClass tmp.LoadValues() 'fill the object with values

Using mem As New IO.MemoryStream ser.Serialize(mem, tmp) 'serialize the data to a memory stream Dim b1() As Byte = mem.ToArray 'extract the data as a byte array fs.Write(BitConverter.GetBytes(b1.Length), 0, 4) 'write the length of the byte array fs.Write(b1, 0, b1.Length) 'write the byte array End Using Next End Using

Using fs As IO.FileStream = IO.File.OpenRead(fn) Dim bDataLen(3) As Byte Do Dim n As Integer = fs.Read(bDataLen, 0, 4) 'read the length If n < bDataLen.Length Then Exit Do 'no more data left

Dim dataLen As Integer = BitConverter.ToInt32(bDataLen, 0) 'create a byte array based on the data length Dim b1() As Byte = CType(Array.CreateInstance(GetType(Byte), dataLen), Byte()) fs.Read(b1, 0, b1.Length) Using mem As New IO.MemoryStream(b1) 'put the data into a memory stream Dim tmp As MyTestClass = CType(ser.Deserialize(mem), MyTestClass) 'deserialize it Console.WriteLine(tmp.ToString) End Using Loop End Using

ScrewTurn Wiki version 2.0.33. Current Page Count: 23. Some of the icons created by FamFamFam.