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.
Hi,thax for your tutorial, it’s very helpfull. But, this is may be incorrect:
I think,it should be like this:
You are correct. I’ve fixed the bug. Thanks for pointing it out!
Why is ther Serializer class non-static, it holds two functions and no globals, I think it would be best if they were static or just put it in the class they are used
I am still a bit new to serialization. Could you please post some sample code for populating your car / owner classes (ie: adding an owner and a couple of cars)?
Sure:
I just set my Owner and Car information to hard coded strings here, but they could just as easily be set from the Text property of a TextBox. The major difference here is that I'm assuming there are properties defined for each variable in the Car and Owner objects. I didn't define them in the tutorial to keep the example code smaller. I hope this helps.
that was great article i learned lots of things about file handling in c# and serialization of objects by this article thanks you so much
You should put this tutorial in the MSDN ISerializable documentation user contributions. Their example code is totally useless for ISerializable noobs.
Sorry if you took that as spam.
No problem Chris, you’re fine - we wouldn’t let it come through if it was spam.
Would this method of saving data to a file be suitable for large amounts of data, say like a few hundred ints, strings, chars, arraylists, and hashtables. Eg; if in the above you had a couple hundred cars and owners, would this still be an efficient way to do this, or is there a beter way to save object data to a file.
cheers Aaron.
I think the above example would work well for up to a few thousand cars. After that point the time required to deserialize might become too long. I haven’t done any testing to determine where the cutoff point is, so I can’t answer for sure. I would say this method would work fine for any amount of data you’d comfortably want to hold in memory at one time (a few megabytes). Any more than that, and you should probably start thinking about a database.
Hello Mr Reddest,
Thanks for a fantastic article. I am going to use this on an engineering parts catalog of about 88,000 individual items. I need to validate the description elements and to ensure the records are accurate and complete before moving them to a new ERP/CAD interface. I will let you all know how well it behaves when I get it working. I don't want to have to mess around with a database as this job only needs to be done once (though I may use the resulting code in some of the ERP Business Logic later).
Thanks again,
Wayne
That was a great example and I was wondering if your readers would like to spice it up a little more by making your Serializer class into a "helper" or "utility" class... I named it FileSerializer for this example.
Now you could take this one step further and use generics.
And here is a slightly revised version of the classes we are using in this example (note, I've dropped the use of a separate serializing class and introduced a way to add serialization to a collection (note: this can be extended to support dictionaries too).
And the example:
I've introduced a few new things and hopefully it helps.
-Scott
Oh ya, one more thing - you may find it necessary to specify security settings on the
GetObjectData. Example:I've tried ur code and had error when I DeSerialize Object:
Error when execute command in DeSerializeObject(...):
Error:
???
Since I last posted, I’ve refined my utility class further; hope this helps
I’ll re-paste my example too…
Note: remove the
PathHelper.BuildPathtoo, these are some other utilities that I wrote; just leave the filename.Here is a revised example:
I’ll re-post the collection example next…
Oh, my bad again… move the \ to after the DeSerialize and before the (
Error when DeSerializer a file:
Error here: The non-generic type ‘Project1.FileSerializer’ cannot be used with type arguments Form1.cs
Sorry, that was due to a typo on my part. Should be…
Hi, :( I've tried so still error when DeSerializer:
Error: Exception has been thrown by the target of an invocation.
Double check the Cars class, making sure that the following method is correct:
Did you notice there was a <? you should replace it with a less-than operator, if you have not already done so.
if you still have problems, try stepping through it and see when it throws an exception - you could add a try\catch block in there to help too.
If you still have problems or you are getting the same error about a non-generic type, make sure that all three statements are:
FileSerializer.DeSerialize <Cars>Hi, I've checked again and everything is the same with your code. Of course I see a < and understand that is less-than quote :(.
And I try cacth the statement:
So cacth:
objectToSerialize always gets null value
Sorry that you are have problems… Since I can not duplicate your problem, I need some more info. Can you replace the catch with this…
and let me know what the error message is, thanks.
OK, And that error is here: (Value of ex.Message) Exception has been thrown by the target of an invocation. I don’t know why that error occur with my progs. Thanks for your helping!
Here is the Cars class
Of course I’ve ommited error checking and proper handling of errors to shorten the example up.
You should add try and catch to the Utility class and could add checking that the class supports serialization. Some errors that could occur: file missing, can not deserialize - was serialized with different content or not of the type T, etc.
Scott, can you send me a example proyect? Thanks :D
Sample Project can be found at http://www.codeproject.com/KB/cs/SerializeUtility.aspx
Hm, I think I get the basic concept. I’m assuming earlier tutorials mentioned need of some sort of libraries, yes? Or a specific compiler mentioned on this website somewhere? Sorry, I’m new to this.
Hi David
The latest code did not paste well, I’ve included a sample download at Code Project.
The current code is in C# with .NET 2.0. I’m currently using Visual Studio 2005, but you should be able to use any C# NET 2.0 compiler.
-Scott
I have never programed before, so I was wondering if you could tell me what to do with my problem. I use HP Image Zone Plus to edit my pictures. I now get the error: Parameter cannot be null. Parameter:serializationStream. I tried uninstalling & reinstalling HP ImageZone, and used HP Support, but was told this was an internal problem. What should I do? Also - anyone know of the best program to use to edit photos?? Or a way to minimize lots of photos at once for email or website purposes instead of one by one? Thanks, Lori
Well Lori, unfortunately I don't have any insight into the error you're seeing. It sounds like a problem with HP Image Zone or your operating system. You could try reinstalling the .NET Framework.
As far as image tools goes, the best one out there by far is Adobe Photoshop. It's a little expensive, but nothing can compare to it in terms of power and features. If you want a free one that will do all of your typical editing needs, go with Paint .NET.
Photoshop will batch edit images for you. We actually have a tutorial here on the blog that demonstrates how to do that. I don't know whether or not Paint .NET has batch processing, but I don't think it does.
The code is misleading. Not everyone needs to implement the ISerializable interface.
This is from MSDN:"If a class needs to control its serialization process, it can implement the ISerializable interface."
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable.aspx
You said "must" here. "Before the Serialize function can be called on ObjectToSerialize we must include the Serializable attribute and it must implement the ISerializable interface." As I said it is optional.
I would say it is recommended for good coding practice.
It's not good practice to implement an interface you don't need. It produces more code you have to care about, thus making it harder to maintain.
A newbee to .NET, Please help
function gives a type conversion error on this line
Sorry about that. There was a typo in the post's code. this.owner is of type Owner, and the code was attempting to cast it to a string. Your line needs to be replaced with:
Thanks for catching that!
Hello everyone,
Does anybody have an experience recording C# objects into HDF5 file format? Does anybody know about recording arbitrary C# objects in HDF5 format?
Thanks a lot, -Gregory
There is a small mistake in the original post, which may be the reason people are having problems with this code.
The correction appears below. Thanks, JB
One more minor thing–for your code to even compile, you must of course place a declaration of objectToSerialize before you instantiate it, as here:
I don't necessarily agree with your suggestions.
There's no reason for the Serializer class to contain a private member for the ObjectToSerialize object. There's no functions or properties to retrieve it and it's not used anywhere else within the class. This is why I chose to simply declare and populate one on the fly within the DeserializeObject function. Unlike C++, that object will not be destructed when it falls out of scope.
In your first example, you'd actually be creating an extra ObjectToSerialize object for no reason when the Serializer class is constructed. The reference would simply be overwritten by a new ObjectToSerialize every time bFormatter.Deserialize(stream) is called.
hii, i like the article you wrote. i also wrote an article on Serialization here : http://kaniks.blogspot.com feel free to post your comments
thanks cheers :)
In this scenario, you are storing List in file and later retreiving it.
I have a case in which I get one object at a time (when someone publishes it) and i have to store it into a file that time. When next object comes (same type), I then send it to same file. So, I am not saving a List but lot of T's in same file.
Now, how do I retreive it? When I keep FileStream.Position = 0, I can get first object by Deserialize method, but how do I get to second object and so on in my file.
Please Help. Thanks in Advance.
It almost sounds like you're trying to use a file in the same way you would a database. So in this scenario, I think a database of some sort would probably be the best answer. SQLite offers a completely free, self-contained database that might work for your needs. There are also C# libraries available for it.
If you're still wanting to use serialization, I would not recommend serializing each object to the end of the file. I would recommend serializing a List of objects and each time you want to add a new one, deserialize the List, add your object to it, then re-serialize the List back to the file. When you want to retrieve it, just deserialize the List and find your object.
This would be the simplest technique, but it would become far too expensive if you're wanting to store several thousands of objects. However, if that were the case, I would then strongly recommend a database.
Thank you for this comprehensive tutorial. It really helped me.
Kristof, from Hungary
Nice examples, however, I would recommend that you properly DISPOSE of your objects after you're through with them.
IMHO - an example is no excuse for sloppy practices ...
Chris, you're 100% correct. I should have surrounded the Stream creation with a using statement to ensure it's disposed. Thanks for pointing it out.
Thank you. You helped me a lot.
Hi, you can also store directly in, and retrieve multiple objects from a single file storage, using NFileStorage, see NFileStorage on CodePlex (100% sources included, all managed c#)
Hi, I've tried the original tutorial code. I seem to have a problem during deserialization.
I've collected all the tutorial source code snippets together to create the enclosed console based application.
The application provides 3 commands i,s,l
To create the scenario run code.exe and type the following, i ..this creates 2 entries i ..this creates 2+2 entries s .. saves the binary data into data3.txt q .. quits the console application
now run code.exe a second time l .. this loads data3.txt
At this point I would expect to see 4 car entries but the console debug indicates that the cars list has zero entries after deserialization. Something obvious is missing in the code but I am a novice to c# so I'm stumped.
The source is contained in a single file called code.cs - see below.
I'm using the microsoft c# command line compiler, csc. So, from the dos command line, to compile, type:- csc code.cs to run, type:- code.exe
Brent, Your code actually works except for a very minor mistake. You are inserting data OK, saving it OK. When you read it back, the function returns a document. You are not using that document that is returned. Look at code snippet below. I have commented out the line you had.
thanks! ;)
Yes. This works.
Can you please explain why we need to implemet ISerializable and realize methods:
public ObjectToSerialize(SerializationInfo info, StreamingContext ctxt); public void GetObjectData(SerializationInfo info, StreamingContext ctxt);
Because it seems the example succesfully works without this explicit serialization, I think attribute [Serializable()] is enough to make it works.
Hi,
You're right... It is not necessary to write these functions for some classes... If the classes contain only simple primitives (which are serializable in turn), and/or if you want to serialize the WHOLE object, then the tag is enough.
However, there are times when your object contains some non-serializable members such as Form or Control references. In this case, your code would crash.
Also, the custom constructor and GetObjectData() allow us to serialize the important members, and then re-construct the rest of the object as we wish when de-serializing. Also, when some of the member objects are non-serializable (Forms, Controls etc), we can use these functions to still de-serialize the other stuff and create these members through new() or something similiar.
Hope this helps...
This was an excellent tutorial. Step by step, clear, organized instructions. Thank you very much!
Hi, is there anyway to serialize a .pdf file to a binary format and save it into an SQL database?
If you want to store the object in an ASCII string format, you can use base 64 encoding.
Untested example:
This is a really good example which I followed to create a file and read it back. However, I had to change one of the variables in the object to a double. Now it creates the file happily, but crashes when it read it back. Is there a problem with serialising doubles? Any advice much appreciated.
Stupid mistake now corrected - code works well for doubles. Sorry to have troubled you.
You need to give examples of serializing to XML in memory. There are plenty of scenarios where you'd want to do this. \ \ http://www.dotnetjohn.com/articles.aspx?articleid=173
Hi,
The tutorial was very useful and educational, but I'm having a problem:
When I serialize, it seems to go through fine, although I suppose it's hard to know that for sure. However, when I try to deserialize, I get:
System.Reflection.TargetInvocationException was unhandled Message="Exception has been thrown by the target of an invocation."
I'm not sure if this is because I'm also trying to serialize/deserialize sub-objects, but I followed the tutorial as much as I could as it pertains to my code.
I have a List, which contains string fields, but one of the fields in each object is a list of a sub-object, which also has two string fields within it. So, I used the AddValue and GetValue for the sub-object in the same way as described. Any ideas? Sorry I couldn't be clearer.
This serializable tutorial is great
Can you please show some sample code with methods of how u can print the List of objects on the console or search for a car as example...im trying to do it but i cant...sorry if it is a newbie question but i am new to c#
Thank you so much.
Instead of using ...
try { ... } finally { stream.Close(); }
... i would suggest taking the using argument. Since Stream implements IDisposable the Close() will then automatically be called. No more finally required and therefore no chance to forget the code.
Thanks So so much. Muito Obrigado
This tutorial is very useful. However, how can i serialize data with type texture2D, as i am now facing a problem that "Type 'Microsoft.Xna.Framework.Graphics.Texture2D' in Assembly 'Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=........' is not marked as serializable."
Can anyone help me or know how to do?
Dont use Texture2D, u only need Texture2D.getdata() and hold in a uint[] variable than serialize this uint[] variable
if you implement the ISerializable using the Serializable attibute is useless, if you don't know this kind of things avoid doing a tuto please
From the SerializableAttribute MSDN documentation:
"Apply the SerializableAttribute attribute even if the class also implements the ISerializable interface to control the serialization process."
this is a real article
http://www.dotnetjohn.com/articles.aspx?articleid=173
enjoy
hey guys, plz help me. so i have two application the first application using for create data the second app using for load and display data i already use "blind to type" but when load have error "Exception has been thrown by the target of an invocation."
here my code when load data :
i guess
in Map class is my problem, maybe...
Map class :
OMG, i solve this bug, lol, tks, it's my mistake when blindtotype
You can find some really easy to understand examples of serialization over here:
http://programming.flashadventures.com/c-sharp/writing-objects-to-files-serialization/
thanks
nice...
good...
Thank you so much this blog was really helpful
This tutorial is excellent! I am working on a MS Cert and this is so much easier to follow than the MS books. Good job!
Hello... I have a .bin file, that has records of two WORDS in it.
Is there a way to deserialize that to a DataTable *or list that contains the Rows of the DataTable* depending on how many records exist in the file?
What I mean is, The file should have something like 02 00 03 00 04 00 05 00 for two records. Without any tags of XML files or anything. How can I deserialize that?
Im still new to this C# stuff. *all of it*
Thanks in advance
My God, so complicated just to write data to a file. Is this evolution of programming?
I wonder how compact serialization is, and how fast it is. I'm currently moving mixed data (int, float, string) around on a local area network. The sender creates a byte stream using BitConverter, UDP's across the network, then decode at the receiver.
I could take the data values and incorporate them into a serializable class, then serialize/deserialize. I wonder about size and speed compared to the encoded binary stream...
Encapsulating into an object would certainly reduce the complexity of encode/decode, but what would be the speed/size cost?
Any thoughts?
John
I don't really see the point in using serialization for this purpose. Nevertheless, I made small test class to do a size comparison.
This class is 331 bytes when serialized into an ASCII format.
A communication string would possibly look something like:
"i=123456789f=1.23456789fs=one two three four five six seven eight nine"
which is roughly 90 bytes in all. This makes the "testBlob" object more than 3.5 times the size.
Without knowing, I'd say parsing the communication string would also take considerably less computing power than deserializing the class.
Serialization has its uses, but this should not be one of them.
Ola
And here with the tags:
[language] i=123456789f=1.23456789fs=one two three four five six seven eight nine [/language]
Is the ability to preview your post too much to ask?
Thanks for the great tutorial! it took me a while for full understanding, but i fully understand it now with enough testing etc.
It is now in great use in my program. really useful.
Thanks for this tutorial, however i get some errors with multiple projects.
I have created a level editor for my game and use serilization to save the different levels, it can write/read fine in the leveledtior, however when i try to load the files in the main game (different project, assembly name etc..) i get an error "Unable to find assembly 'TileLevelEditor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'."
I assume this is since the serilization writes some assembly information to the file.
So how do i use my files in different projects? Thanks
OMG! So baffled why cant things be easy
Thanks for your contribution. Please find the below simple example to understand esialy.
Thank you uppu. it's very simple and great example. We can run this with out any errors.
Thank you for the same.
Yes, great tutorial!
I have a librarysystem. I have books which save an objekt of a customer so you know who borrowed the book, as a car nows who its owner is.
The customer has a list of book-objekts so they can save the books they borrow.
Can I use this then and how should I implement it?
What if two cars reference to one owner? When the xml is deserialized, will it create two owners?
This tutorial uses the binary serializer, which will correctly maintain the references when deserialized. The XML serializer, on the other hand, will create two copies of the Owner object when serialized.
Thank you. This post answered all of the questions I had about updating a dataset. Very useful. http://www.dapfor.com/en/net-suite/net-grid/tutorial/headers-and-columns
This is a very nice tutorial. Please tell me if I can store more than one object and get them one by one using this code. Thanks
I do not believe you have random access to the data being stored. If that's your need, I would highly recommend considering a database.
For the examples in boxes 5 and 6, where would that code need to be located? Inside it's own .cs file? Or located inside one of the others you created?