amigo
amigo

Reputation: 155

C# - Serialize/Deserialize or Save/Load a list of tuples

I have a list which contains a Tuple of two strings and 25.000 elements

List<Tuple<string, string>> MyList

I try to find a way to save this list and then load it because really takes time each time to construct from the beginning the MyList. I tried

using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;

namespace CopyFiles
{
/// <summary>
/// Serializer class.  Load and Save classes from/to XML files.
/// </summary>

public class XSerial
{
    /// <summary>
    /// Load a class from a serialized XML file.
    /// </summary>
    /// <param name="filename">full path or path relative to the XML file</param>
    /// <param name="t">type of the class that is being retrieved (Use typeof(ClassName))</param>
    /// <returns>A populated version of the class, or null on failure</returns>
    /// <exception cref="Exception">Can throw several exceptions for IO and serialization loading</exception>
    public static T Load<T>(string filename)
    {
        T ob = default(T);
        using (Stream s = File.Open(filename, FileMode.Open))
        {
            StreamReader sr = new StreamReader(s);
            ob = DeserializeObject<T>(sr.ReadToEnd());
            s.Close();
        }
        return ob;
    }

    /// <summary>
    /// Save an instance of a class to an XML file
    /// </summary>
    /// <param name="filename">Full or relative path to the file</param>
    /// <param name="cls">Class to serialize and save.</param>
    /// <param name="t">Type of the class (use: typeof(ClassName)</param>
    /// <returns>True on success, False on failure</returns>
    public static void Save<T>(string filename, T cls)
    {
        using (Stream s = File.Open(filename, FileMode.Create))
        {
            using (StreamWriter sw = new StreamWriter(s))
            {
                sw.Write(SerializeObject<T>(cls));
                sw.Close();
                s.Close();
                return;
            }
        }
    }


    /// <summary>
    /// Serialize the object into an XML format
    /// </summary>
    /// <typeparam name="T">Type of object to serialize</typeparam>
    /// <param name="pObject">the object to serialize</param>
    /// <returns>a string representing the XML version of the object</returns>
    public static String SerializeObject<T>(T pObject)
    {
        MemoryStream memoryStream = new MemoryStream();
        UTF8Encoding encoding = new UTF8Encoding();

        XmlSerializer xs = new XmlSerializer(typeof(T));
        System.Xml.XmlTextWriter xmlTextWriter = new System.Xml.XmlTextWriter(memoryStream, Encoding.UTF8);
        xs.Serialize(xmlTextWriter, (object)pObject);
        memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
        return encoding.GetString(memoryStream.ToArray());
    }

    /// <summary>
    /// Deserialize the object back into the object from an XML string
    /// </summary>
    /// <typeparam name="T">Type of the object to restore</typeparam>
    /// <param name="pXmlizedString">The string that represents the object in XML</param>
    /// <returns>A new instance of the restored object</returns>
    public static T DeserializeObject<T>(String pXmlizedString)
    {
        UTF8Encoding encoding = new UTF8Encoding();
        XmlSerializer xs = new XmlSerializer(typeof(T));
        MemoryStream memoryStream = new MemoryStream(encoding.GetBytes(pXmlizedString));
        System.Xml.XmlTextWriter xmlTextWriter = new System.Xml.XmlTextWriter(memoryStream, Encoding.UTF8);
        return (T)xs.Deserialize(memoryStream);
    }
  }
}

which is working perfect for simple List<...>

class Program
{
    static void Main(string[] args)
    {
        List<string> MyList = null;
        try
        {
            MyList = XSerial.Load<List<string>>("MyList.xml");
        }
        catch (Exception e)
        {
            Console.WriteLine("Error: " + e.Message);
            // make sure the object won't cause errors.
            MyList = new List<string>();
        }

        Console.WriteLine("List Items:");
        foreach (string item in MyList)
        {
            Console.WriteLine("In list: " + item);
        }

        MyList.Add("Orange");
        MyList.Add("Blue");
        MyList.Add("Green");

        Console.WriteLine("Saving list...\n");
        try
        {
            XSerial.Save<List<string>>("MyList.xml", MyList);
        }
        catch (Exception e)
        {
            Console.WriteLine("Error Saving: " + e.Message);
            // nothing can be done about recovery.
        }

        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();
    }
}

but not for a list with tuple because XmlSerializer to be able to do it's job needs a default constructor. That is a constructor that takes no arguments. All the Tuple<...> classes have a single constructor and that constructor takes a number of arguments.

My Question: Is there any way the above XSerial to do the job for a list of tuples or should i use something else like http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx ? Thanks in advance.

Upvotes: 2

Views: 4474

Answers (2)

amigo
amigo

Reputation: 155

I concluded to use the following (binary seriliazation) for the case list with tuples

 List<Tuple<string, string>> MyList

My code

 List<Tuple<string, string>> MyList = new List<Tuple<string, string>>(); 

 if (File.Exists(@"filename.dat"))
        {
            //LOAD
            Console.WriteLine("Load filename.dat...");
            FileStream inStr = new FileStream(@"filename.dat", FileMode.Open);
            BinaryFormatter bf = new BinaryFormatter();
            MyList = bf.Deserialize(inStr) as List<Tuple<string, string>>;

        }
        else {
            //
            // Do here the list building/ Make the List<Tuple<string, string>> MyList
            //

            //SAVE
            FileStream stream = new FileStream(@"filename.dat", FileMode.Create);
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, MyList);
            stream.Close();            
        }

In my case and in my Laptop the list building takes approx 6 min (~33.000 tuple elements) and from the time that i have the "filename.dat" does only 1 sec to load it for further usage in my program.

Upvotes: 2

Thomas Weller
Thomas Weller

Reputation: 11717

If performance is a concern then the JSON format along with the JSON.Net framework should be better for your needs. Also, what's at least equally important, JSON.Net should work out of the box for you.

Upvotes: 0

Related Questions