How to: Serialize Data
This example demonstrates how to use the XmlSerializer class to write data in a custom class to a save game, and how to load the data from the file.
To define save game data
- Define a new class or struct. The size of this class will determine the size of your save game files, so try to keep the class small. Do not reference other objects from this class unless you want to serialize them as well.
- Add the Serializable attribute to the class.
[Serializable]
public struct SaveGameData
{
public string PlayerName;
public Vector2 AvatarPosition;
public int Level;
public int Score;
}
To serialize data to a save game file
- Create a StorageContainer to access the specified device.
- Use Path.Combine to create a new string specifying the full path to the save game file.
- Open a FileStream object on the file using the File.Open method from the System.IO namespace. Specifying FileMode.OpenOrCreate tells Open to create the save game if it doesn't exit.
- Create an XmlSerializer object, passing the type of the structure that defines your save game data.
- Call Serialize, passing the FileStream and the data to serialize. The XmlSerializer will turn the data in the structure into XML and use the FileStream to write the data into the file.
- Close the FileStream.
- Dispose the StorageContainer to commit the changes to the device.
// Note: Before you can build this file in a project, you must
// add a reference to System.xml. To to this, right-click
// on References in Solution Explorer and click Add Reference.
// In the .NET pane, scroll down and select System.Xml.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using System.IO;
using System.Xml.Serialization;
private static void DoSaveGame( StorageDevice device )
{
// Create the data to save
SaveGameData data = new SaveGameData();
data.PlayerName = "Hiro";
data.AvatarPosition = new Vector2( 360, 360 );
data.Level = 11;
data.Score = 4200;
// Open a storage container
StorageContainer container =
device.OpenContainer( "StorageDemo" );
// Get the path of the save game
string filename = Path.Combine( container.Path, "savegame.sav" );
// Open the file, creating it if necessary
FileStream stream = File.Open( filename, FileMode.OpenOrCreate );
// Convert the object to XML data and put it in the stream
XmlSerializer serializer = new XmlSerializer( typeof( SaveGameData ) );
serializer.Serialize( stream, data );
// Close the file
stream.Close();
// Dispose the container, to commit changes
container.Dispose();
}
To read serialized data from a save game file
- Create a StorageContainer to access the specified device.
- Use Path.Combine to create a new string specifying the full path to the save game file.
- Call File.Exists to determine if the save game exists.
- Open a FileStream object on the file using the File.Open method from the System.IO namespace.
- Create an XmlSerializer object, passing the type of the structure that defines your save game data.
- Call Deserialize, passing the FileStream object. Deserialize returns a copy of the save game structure populated with the data from the save game file. (You will have to cast the return value from Object to your type).
- Close the FileStream.
- Dispose the StorageContainer.
The Complete Example
// Note: Before you can build this file in a project, you must
// add a reference to System.xml. To to this, right-click
// on References in Solution Explorer and click Add Reference.
// In the .NET pane, scroll down and select System.Xml.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using System.IO;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Content;
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
ContentManager content;
public Game1()
{
graphics = new GraphicsDeviceManager( this );
content = new ContentManager( Services );
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadGraphicsContent( bool loadAllContent )
{
if (loadAllContent)
{
// TODO: Load any ResourceManagementMode.Automatic content
}
}
protected override void UnloadGraphicsContent( bool unloadAllContent )
{
if (unloadAllContent == true)
{
content.Unload();
}
}
bool ShowingStorageDeviceGuide = false;
IAsyncResult result;
Object stateobj;
bool GameSaveRequested = false;
protected override void Update( GameTime gameTime )
{
// Allows the default game to exit on Xbox 360 and Windows
if (GamePad.GetState( PlayerIndex.One ).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (GamePad.GetState( PlayerIndex.One ).Buttons.A == ButtonState.Pressed)
{
// Set the request flag
GameSaveRequested = true;
result = StorageDevice.BeginShowStorageDeviceGuide( PlayerIndex.One, null, null );
}
if (GamePad.GetState( PlayerIndex.One ).Buttons.B == ButtonState.Pressed)
{
// Reset the device
device = null;
AsyncCallback ac = new AsyncCallback( this.GetDevice );
stateobj = (Object)"GetDevice for Player One";
StorageDevice.BeginShowStorageDeviceGuide(
PlayerIndex.One, ac, stateobj );
}
// If a save is pending, save as soon as the
// storage device is chosen
if ((GameSaveRequested) && (result.IsCompleted))
{
StorageDevice device = StorageDevice.EndShowStorageDeviceGuide( result );
if (device.IsConnected)
{
DoSaveGame( device );
DoLoadGame( device );
DoCreate( device );
DoOpen( device );
DoCopy( device );
DoEnumerate( device );
DoRename( device );
DoDelete( device );
DoOpenFile();
}
// Reset the request flag
GameSaveRequested = false;
}
if (GamePad.GetState( PlayerIndex.One ).Buttons.X == ButtonState.Pressed)
{
// make sure we don't call BeginShowStorageDeviceGuide when the guide
// is already being shown
if (!ShowingStorageDeviceGuide)
{
ShowingStorageDeviceGuide = true;
// reset the device
device = null;
result = StorageDevice.BeginShowStorageDeviceGuide( PlayerIndex.One, null, null );
while (!result.IsCompleted)
{
// Call Update and Draw to draw the guide
this.Tick();
}
device = StorageDevice.EndShowStorageDeviceGuide(result);
if (device.IsConnected)
{
DoSaveGame( device );
DoLoadGame( device );
DoCreate( device );
DoOpen( device );
DoCopy( device );
DoEnumerate( device );
DoRename( device );
DoDelete( device );
DoOpenFile();
}
ShowingStorageDeviceGuide = false;
}
}
base.Update( gameTime );
}
StorageDevice device;
void GetDevice( IAsyncResult result )
{
device = StorageDevice.EndShowStorageDeviceGuide( result );
if (device.IsConnected)
{
DoSaveGame( device );
DoLoadGame( device );
DoCreate( device );
DoOpen( device );
DoCopy( device );
DoEnumerate( device );
DoRename( device );
DoDelete( device );
DoOpenFile();
}
}
protected override void Draw( GameTime gameTime )
{
graphics.GraphicsDevice.Clear( Color.CornflowerBlue );
base.Draw( gameTime );
}
[Serializable]
public struct SaveGameData
{
public string PlayerName;
public Vector2 AvatarPosition;
public int Level;
public int Score;
}
private static void DoSaveGame( StorageDevice device )
{
// Create the data to save
SaveGameData data = new SaveGameData();
data.PlayerName = "Hiro";
data.AvatarPosition = new Vector2( 360, 360 );
data.Level = 11;
data.Score = 4200;
// Open a storage container
StorageContainer container =
device.OpenContainer( "StorageDemo" );
// Get the path of the save game
string filename = Path.Combine( container.Path, "savegame.sav" );
// Open the file, creating it if necessary
FileStream stream = File.Open( filename, FileMode.OpenOrCreate );
// Convert the object to XML data and put it in the stream
XmlSerializer serializer = new XmlSerializer( typeof( SaveGameData ) );
serializer.Serialize( stream, data );
// Close the file
stream.Close();
// Dispose the container, to commit changes
container.Dispose();
}
private static void DoLoadGame( StorageDevice device )
{
// Open a storage container
StorageContainer container =
device.OpenContainer( "StorageDemo" );
// Get the path of the save game
string filename = Path.Combine( container.Path, "savegame.sav" );
// Check to see if the save exists
if (!File.Exists( filename ))
// Notify the user there is no save
return;
// Open the file
FileStream stream = File.Open( filename, FileMode.OpenOrCreate,
FileAccess.Read );
// Read the data from the file
XmlSerializer serializer = new XmlSerializer( typeof( SaveGameData ) );
SaveGameData data = (SaveGameData)serializer.Deserialize( stream );
// Close the file
stream.Close();
// Dispose the container
container.Dispose();
// Report the data to the console
Console.WriteLine( "Name: " + data.PlayerName );
Console.WriteLine( "Level: " + data.Level.ToString() );
Console.WriteLine( "Score: " + data.Score.ToString() );
Console.WriteLine( "Position: " + data.AvatarPosition.ToString() );
}
private static void DoCreate( StorageDevice device )
{
// Open a storage container
StorageContainer container =
device.OpenContainer( "StorageDemo" );
// Add the container path to our filename
string filename = Path.Combine( container.Path, "demobinary.sav" );
// Create a new file
if (!File.Exists( filename ))
{
FileStream file = File.Create( filename );
file.Close();
}
// Dispose the container, to commit the data
container.Dispose();
}
private static void DoOpen( StorageDevice device )
{
// Open a storage container
StorageContainer container =
device.OpenContainer( "StorageDemo" );
// Add the container path to our filename
string filename = Path.Combine( container.Path, "demobinary.sav" );
FileStream file = File.Open( filename, FileMode.Open );
file.Close();
// Dispose the container
container.Dispose();
}
private static void DoCopy( StorageDevice device )
{
// Open a storage container
StorageContainer container =
device.OpenContainer( "StorageDemo" );
// Add the container path to our filename
string filename = Path.Combine( container.Path, "demobinary.sav" );
string copyfilename = Path.Combine( container.Path, "copybinary.sav" );
File.Copy( filename, copyfilename, true );
// Dispose the container, to commit the change
container.Dispose();
}
private static void DoRename( StorageDevice device )
{
// Open a storage container
StorageContainer container =
device.OpenContainer( "StorageDemo" );
// Add the container path to our filename
string oldfilename = Path.Combine( container.Path, "demobinary.sav" );
string newfilename = Path.Combine( container.Path, "renamebinary.sav" );
if (!File.Exists( newfilename ))
File.Move( oldfilename, newfilename );
// Dispose the container, to commit the change
container.Dispose();
}
private static void DoEnumerate( StorageDevice device )
{
// Open a storage container
StorageContainer container =
device.OpenContainer( "StorageDemo" );
ICollection<string> FileList = Directory.GetFiles( container.Path );
// Dispose the container
container.Dispose();
}
private static void DoDelete( StorageDevice device )
{
// Open a storage container
StorageContainer container =
device.OpenContainer( "StorageDemo" );
// Add the container path to our filename
string filename = Path.Combine( container.Path, "demobinary.sav" );
// Delete the new file.
if (File.Exists( filename ))
File.Delete( filename );
// Dispose the container, to commit the change
container.Dispose();
}
private static void DoOpenFile()
{
FileStream file = OpenTitleFile(
"Sprite.dds", FileMode.Open, FileAccess.Read );
Console.WriteLine( "File Size: " + file.Length );
file.Close();
}
private static FileStream OpenTitleFile(
string filename, FileMode mode, FileAccess access )
{
string fullpath = Path.Combine( StorageContainer.TitleLocation, filename );
return File.Open( fullpath, mode, access );
}
}