Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm making a game and I am serializing the save game data. The data is simply a few lists of bools, ints and floats.

But about 50% of the time I get an error when the data tries to save or load that says "There is an error in XML document." The error is always located at the end of the file, even after it has changed size or I have added other variables.

It appears that very last part of the XML data is getting copied twice. The last line of the XML should read:

</LevelStats>

But when an error occurs it often reads

</LevelStats>>

Or

</LevelStats>tats>

Or some other small part of the last line duplicated.

Here is the class I am serializing:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Storage;
using System.IO;

namespace Jetpack.Classes
{
    [Serializable]
    public struct LevelStats
    {
        // Player Bests
        public List<float?> fTimeList;
        public List<int?> iScoreList;
        public List<int?> iFuelList;

        // Time
        public List<bool> bBronzeTimeList;
        public List<bool> bSilverTimeList;
        public List<bool> bGoldTimeList;

        // Score
        public List<bool> bBronzeScoreList;
        public List<bool> bSilverScoreList;
        public List<bool> bGoldScoreList;

        // Fuel
        public List<bool> bBronzeFuelList;
        public List<bool> bSilverFuelList;
        public List<bool> bGoldFuelList;

        // Level Complete
        public List<bool> bIsLevelComplete;
    }
}

And here are my methods for saving the loading the data:

region Save & Load Level Stats
    public static void SaveLevelStats(LevelStats levelStats, string filename)
    {
        // Get the path of the save game
        string fullpath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), filename);

        // Open the file, creating it if necessary
        FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate);
        try
        {
            // Convert the object to XML data and put it in the stream
            XmlSerializer serializer = new XmlSerializer(typeof(LevelStats));
            serializer.Serialize(stream, levelStats);
        }
        finally
        {
            // Close the file
            stream.Close();
        }
    }

    public static LevelStats LoadLevelStats(string filename)
    {
        LevelStats levelStats;

        // Get the path of the save game
        string fullpath = System.IO.Path.Combine((Directory.GetCurrentDirectory()), filename);

        // Open the file
        FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate,
        FileAccess.Read);
        try
        {
            // Read the data from the file
            XmlSerializer serializer = new XmlSerializer(typeof(LevelStats));
            levelStats = (LevelStats)serializer.Deserialize(stream);
        }
        finally
        {
            // Close the file
            stream.Close();
        }

        return (levelStats);
    }

    #endregion

Why am I getting the error above?

share|improve this question

1 Answer 1

up vote 4 down vote accepted

You're seeing bits of the previous version of the file. In your SaveLevelStats function, change your call to File.Open from

FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate);

to

FileStream stream = File.Open(fullpath, FileMode.Create);

FileMode.OpenOrCreate does not cause truncation of the opened file. That is, when you open the file and it already exists, the existing data is left intact. The returned stream still points to the beginning of the file, however. So when you happen to write an XML state that is shorter than the previously-saved state, you get bits of the previous file left over.

To solve this, want to use a different version of the FileMode enumeration when you call File.Open: Create, which

Specifies that the operating system should create a new file. If the file already exists, it will be overwritten. This requires FileIOPermissionAccess.Write permission. FileMode.Create is equivalent to requesting that if the file does not exist, use CreateNew; otherwise, use Truncate. If the file already exists but is a hidden file, an UnauthorizedAccessException exception is thrown.

share|improve this answer
    
Thank you, very well explained and it did the job! –  Jon Dunn Dec 17 '13 at 8:29

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.