C# Tutorial - Serialize Objects to a File

While storing information in memory is great, there comes a time your users will have to shut your application down. This means (probably) that you will need to write information to a file at some point, because you will want to store whatever data was in memory. Today, we are going to take a look at a feature built into .NET called Serialization that makes writing and reading data structures to and from a file extremely easy.

For this example, let's say I want to create a program that keeps track of all the cars my friends own. I'm going to create two objects to achieve this: Car and Owner. The Car object will store the make, model, and year of the car. The Owner object will save some information about who owns the car. Each Car object will hold a reference to an Owner object.

//information about the car
public class Car
{
   private string make;
   private string model;
   private int year;
   private Owner owner;

   public Car()
   {
   }
}

//information about the car's owner
public class Owner
{
   private string firstName;
   private string lastName;

   public Owner()
   {
   }
}

Since most of us have more than one friend, we're going to need to create a List of Car objects.

List<Car> cars = new List<Car>();

Now that we have our objects created, we're almost ready to serialize them. When I save data to files, I like to create an object specifically to hold all the things I want to serialize.

public class ObjectToSerialize
{
   private List<Car> cars;

   public List<Car> Cars
   {
      get { return this.cars; }
      set { this.cars = value; }
   }

   public ObjectToSerialize()
   {
   }
}

This class holds a reference to every object we'll want to serialize. In this case, the only thing we want to save is the list of cars. Now lets create the functions that will perform the serialization and deserialization of our object. I usually create a Serializer class to control the writing and reading to and from files.

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

public class Serializer
{
   public Serializer()
   {
   }

   public void SerializeObject(string filename, ObjectToSerialize objectToSerialize)
   {
      Stream stream = File.Open(filename, FileMode.Create);
      BinaryFormatter bFormatter = new BinaryFormatter();
      bFormatter.Serialize(stream, objectToSerialize);
      stream.Close();
   }

   public ObjectToSerialize DeSerializeObject(string filename)
   {
      ObjectToSerialize objectToSerialize;
      Stream stream = File.Open(filename, FileMode.Open);
      BinaryFormatter bFormatter = new BinaryFormatter();
      objectToSerialize = (ObjectToSerialize)bFormatter.Deserialize(stream);
      stream.Close();
      return objectToSerialize;
   }
}

As you can see, the actual code required to serialize an object is relatively small and simple. At this point, however, the code will not build. Before the Serialize function can be called on ObjectToSerialize we must include the Serializable attribute and it must implement the ISerializable interface.

using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable()]
public class ObjectToSerialize : ISerializable
{
   private List<Car> cars;

   public List<Car> Cars
   {
      get { return this.cars; }
      set { this.cars = value; }
   }

   public ObjectToSerialize()
   {
   }

   public ObjectToSerialize(SerializationInfo info, StreamingContext ctxt)
   {
      this.cars = (List<Car>)info.GetValue("Cars", typeof(List<Car>));
   }

   public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
   {
      info.AddValue("Cars", this.cars);
   }
}

As part of the ISerializable interface, the class must include another constructor for deserializing the object and a function GetObjectData which describes how to serialize the object. Since the Car and Owner objects are also being serialized, they will also need to implement these functions.

[Serializable()]
public class Car : ISerializable
{
   private string make;
   private string model;
   private int year;
   private Owner owner;

   public Car()
   {
   }

   public Car(SerializationInfo info, StreamingContext ctxt)
   {
      this.make = (string)info.GetValue("Make", typeof(string));
      this.model = (string)info.GetValue("Model",typeof(string));
      this.year = (string)info.GetValue("Year", typeof(int));
      this.owner = (Owner)info.GetValue("Owner", typeof(Owner));
   }

   public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
   {
      info.AddValue("Make", this.make);
      info.AddValue("Model", this.model);
      info.AddValue("Make", this.year);
      info.AddValue("Owner", this.owner);
   }
}


[Serializable()]
public class Owner : ISerializable
{
   private string firstName;
   private string lastName;

   public Owner()
   {
   }

   public Owner(SerializationInfo info, StreamingContext ctxt)
   {
      this.firstName = (string)info.GetValue("FirstName", typeof(string));
      this.lastName = (string)info.GetValue("LastName", typeof(string));
   }

   public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
   {
      info.AddValue("FirstName", this.firstName);
      info.AddValue("LastName", this.lastName);
   }
}

Now, to save the list of objects to a file, all that needs to be done is to call the Serialize and DeSerialize functions of the Serializer class.

List<Car> cars = new List<Car>();

//save the car list to a file
ObjectToSerialize objectToSerialize = new ObjectToSerialize();
objectToSerialize.Cars = cars;

Serializer serializer = new Serializer()
serializer.SerializeObject("outputFile.txt", objectToSerialize);

//the car list has been saved to outputFile.txt
//read the file back from outputFile.txt

objectToSerialize = serializer.DeSerializeObject("outputFile.txt");
cars = objectToSerialize.Cars;

That is all that's required to save and load custom C# objects to a binary file. Just like any file, it is possible for your files to become corrupted. Because of this, it is probably a good idea to add some error handling whenever output from the file is being cast to an object.

ref :  http://www.switchonthecode.com/tutorials/csharp-tutorial-serialize-objects-to-a-file

0 nhận xét :

Đăng nhận xét