C# Custom Serialization/Deserialization together with DeflateStreams

vesz picture vesz · Nov 28, 2010 · Viewed 8.1k times · Source

I'm trying to do custom serialization/deserialization of an object as well as compressing/decompressing the serialized data with DeflateStreams. I originally did this for more complex objects but cut it down to try and figure out the problem, however it just became more puzzling as it is still there. Here is the class to be serialized/deserialized:

[Serializable]
    public class RandomObject : ISerializable
    {
        public String Name { get; set; }
        public String SavePath { get; set; }

        public RandomObject()
        {
        }

        public RandomObject(String name, String savepath)
        {
            Name = name;
            SavePath = savepath;
        }

        public RandomObject(SerializationInfo info, StreamingContext context)
            : this(info.GetString("name"), info.GetString("savepath"))
        {
        }
        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("name", Name);
            info.AddValue("savepath", SavePath);
        }
    }

And here is the code that is supposed to serialize it(which seems to work):

BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                bf.Serialize(ms, profile);
                using (DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress))
                {
                    try
                    {
                        using (FileStream fs = File.Create(path))
                        {
                            ds.Flush();
                            Miscellaneous.CopyStream(ds.BaseStream, fs);
                            fs.Flush();
                            fs.Close();
                        }
                    }
                    catch (IOException e)
                    {
                        MessageBox.Show(e.Message);
                        success = false;
                    }
                    ds.Close();
                }
                ms.Close();
            }

And here is the deserialization:

RandomObject profile = null;
                using (FileStream fs = File.OpenRead(path))
                {
                    using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress))
                    {
                        BinaryFormatter bf = new BinaryFormatter();
                        ds.Flush();

                        using (MemoryStream ms = new MemoryStream())
                        {
                            Miscellaneous.CopyStream(ds.BaseStream, ms);
                            profile = bf.Deserialize(ms) as RandomObject;
                            profile.SavePath = path;
                            ms.Close();
                        }
                        ds.Close();
                    }
                    fs.Close();
                }

Now, to the problem. Deserialization throws a SerializationException with the message {"No map for object '201326592'."} I have no idea how to troubleshoot or figure out what exactly is causing the problem. Very basic serialization works when I just run BinaryFormatter's Serialize and Deserialize methods on the same MemoryStream.

I tried removing the DeflateStream stuff from both methods, but it's still the same problem. When I look at the examples at MSDN and other places it looks like I'm doing it just right, and googling for the exception message doesn't give any meaningful results(or perhaps I'm just bad at searching).

PS. As you can see I use Miscellaneous.CopyStream(src, dest) which is a basic stream copier, as I can't get src.CopyTo(dest) to work at all, so any hints on that is welcome as well.

Below is a link to the whole VS2010 project if you would like to look at it more closely: http://www.diredumplings.com/SerializationTesting.zip

UPDATE:

The_Smallest: I tried using the Compress method you posted on my serialization:

BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream stream = new MemoryStream())
            {
                bf.Serialize(stream, profile);

                byte[] array = Compress(stream);

                using (MemoryStream ms = new MemoryStream(array))
                {
                    using (FileStream fs = File.Create(path))
                    {
                        ms.WriteTo(fs);
                        fs.Flush();
                    }
                }
            }

However, it seems to give me the same problems that I had with srcStream.CopyTo(destStream) earlier, which is that it doesn't seem to get written to the stream. The result is a 0 kb file when I try to save it to disk. Any ideas?

Pieter: I removed the MemoryStream from the deserialization method and it seems have the same functionality as before. However I'm not sure how to implement the serialization the way you suggested. Is this what you had in mind?

BinaryFormatter bf = new BinaryFormatter();

            using (FileStream fs = File.Create(path))
            {
                using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress))
                {
                    bf.Serialize(ds, profile);
                    fs.Flush();
                    ds.Close();
                }
                fs.Close();
            }

Thanks to both of you!

Answer

Pieter van Ginkel picture Pieter van Ginkel · Nov 28, 2010

You should serialize into the DeflateStream, not the base (MemoryStream) stream.

For serializing: begin with the File.Create. Then around that stream, create the DeflateStream. Then to the DefaulteStream, serialize your objects.

For deserializing: do not create the MemoryStream and deserialize directly from the DeflateStream.

I believe there is no need for the added MemoryStream. If however you do have problems writing directly to/reading directly from the file streams, just change the serialize routine to write to the DeflateStream instead of the MemoryStream.

That should solve your issues.