Example of xml vs binary serialization coupled with GZip compression. Note
that I tweaked a few things, and really a List<T> isn't going to cut it
(since the parent can be bypassed); output lengths first for comparison:
Xml 1638
Xml (GZip) 381
Bin 4846
Bin (GZip) 2518
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.ObjectModel;
using System.Text;
static class Program
{
static void Main(string[] args)
{
Node<int> tree = new Node<int>();
Random rand = new Random(123456);
for (int i = 0; i < 5; i++)
{
tree.Add(rand.Next(50));
tree.Add(rand.Next(50)).Add(rand.Next(50));
Node<int> node = tree.Add(rand.Next(50));
node.Add(rand.Next(50));
node.Add(rand.Next(50));
}
byte[] xml, bin, xmlZip, binZip;
using (MemoryStream ms = new MemoryStream())
{
using (XmlWriter writer = XmlWriter.Create(ms))
{
XmlSerializer xs = new XmlSerializer(tree.GetType());
xs.Serialize(writer, tree);
writer.Close();
}
xml = ms.ToArray();
}
using (MemoryStream ms = new MemoryStream())
{
using(GZipStream zip = new GZipStream(ms,
CompressionMode.Compress, true))
using (XmlWriter writer = XmlWriter.Create(zip))
{
XmlSerializer xs = new XmlSerializer(tree.GetType());
xs.Serialize(writer, tree);
writer.Close();
zip.Close();
}
xmlZip = ms.ToArray();
}
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, tree);
bin = ms.ToArray();
}
using (MemoryStream ms = new MemoryStream())
{
using (GZipStream zip = new GZipStream(ms,
CompressionMode.Compress, true))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(zip, tree);
zip.Close();
}
binZip = ms.ToArray();
}
Console.WriteLine("Xml {0}", xml.Length);
Console.WriteLine("Xml (GZip) {0}", xmlZip.Length);
Console.WriteLine("Bin {0}", bin.Length);
Console.WriteLine("Bin (GZip) {0}", binZip.Length);
// show the actual xml
Console.WriteLine();
Console.WriteLine(Encoding.UTF8.GetString(xml));
Console.WriteLine();
// prove we can decompress the Xml GZip
using (MemoryStream ms = new MemoryStream(xmlZip))
using (GZipStream zip = new GZipStream(ms,
CompressionMode.Decompress))
using (XmlReader reader = XmlReader.Create(zip))
{
XmlSerializer xs = new XmlSerializer(typeof(Node<int>));
Node<int> node = (Node<int>) xs.Deserialize(reader);
WriteNode(node, 0);
}
}
static void WriteNode<T>(Node<T> node, int indent)
{
string prefix = new string(' ', indent * 2);
Console.WriteLine("{0}Value: {1}", prefix, node.Value);
foreach (Node<T> child in node.Nodes)
{
WriteNode(child, indent + 1);
}
}
}
[Serializable, XmlRoot("Nodes")]
public class NodeCollection<T> : Collection<Node<T>>
{
private readonly Node<T> parent;
[XmlIgnore]
public Node<T> Parent { get { return parent; } }
public NodeCollection(Node<T> parent) {
this.parent = parent;
}
protected override void InsertItem(int index, Node<T> item)
{
base.InsertItem(index, item);
this[index].Parent = this.Parent;
}
protected override void RemoveItem(int index)
{
this[index].Parent = null;
base.RemoveItem(index);
}
protected override void SetItem(int index, Node<T> item)
{
this[index].Parent = null;
base.SetItem(index, item);
this[index].Parent = this.Parent;
}
}
[Serializable, XmlRoot("Tree")]
public class Node<T>
{
[XmlAttribute]
public T Value { get; set; } // Value at this node
private Node<T> parent;// Contains the parent node
[XmlIgnore]
public Node<T> Parent
{
get { return parent; }
internal set { parent = value; }
}
private NodeCollection<T> nodes; // Container for Nodes
public NodeCollection<T> Nodes
{
get
{
if (nodes == null) nodes = new NodeCollection<T>(this);
return nodes;
}
}
public Node<T> Add(T value)
{
Node<T> node = new Node<T>();
node.Value = value;
Nodes.Add(node);
return node;
}
private static readonly List<Node<T>> Empty = new List<Node<T>>();
// note still allows foreach ;-p
public IEnumerator<Node<T>> GetEnumerator()
{
if (nodes == null) return Empty.GetEnumerator();
return nodes.GetEnumerator();
}
}