2011-03-14 74 views
8

我正在使用XmlDictionaryWriter將對象序列化爲數據與數據約定序列化程序的數據庫。 它效果很好,尺寸和速度都比使用text/xml好2倍。使用預共享字典的.NET二進制XML

但是,我將不得不在數據庫中處理大量的記錄,其中任何額外的字節都會直接轉換爲數據庫大小的千兆字節。 這就是爲什麼我希望通過使用XML字典進一步縮小尺寸的原因。

我該怎麼做?

我看到XmlDictionaryWriter.CreateBinaryWriter靜態方法接受類型爲IXmlDictionary的2-nd參數。 MSDN說「用作共享字典的XmlDictionary」。

我第一次嘗試使用系統提供的實現:

XmlDictionary dict = new XmlDictionary(); 
string[] dictEntries = new string[] 
{ 
    "http://schemas.datacontract.org/2004/07/MyContracts", 
    "http://www.w3.org/2001/XMLSchema-instance", 
    "MyElementName1", 
    "MyElementName2", 
    "MyElementName3", 
}; 
foreach (string s in dictEntries) 
     dict.Add(s); 

結果是.NET框架完全忽略了字典,並且仍然插入上述字符串以純文本格式,而不是隻引用相應的字典條目。

然後,我已經建立了我自己的實現IXmlDictionary的:

class MyDictionary : IXmlDictionary 
{ 
    Dictionary<int, string> values = new Dictionary<int, string>(); 
    Dictionary<string, int> keys = new Dictionary<string, int>(); 

    MyDictionary() 
    { 
     string[] dictEntries = new string[] 
     { 
      "http://schemas.datacontract.org/2004/07/MyContracts", 
      "http://www.w3.org/2001/XMLSchema-instance", 
      "MyElementName1", 
      "MyElementName2", 
      "MyElementName3", 
     }; 

     foreach (var s in dictEntries) 
      this.Add(s); 
    } 

    static IXmlDictionary s_instance = new MyDictionary(); 
    public static IXmlDictionary instance { get { return s_instance; } } 

    void Add(string val) 
    { 
     if (keys.ContainsKey(val)) 
      return; 
     int id = values.Count + 1; 
     values.Add(id, val); 
     keys.Add(val, id); 
    } 

    bool IXmlDictionary.TryLookup(XmlDictionaryString value, out XmlDictionaryString result) 
    { 
     if (value.Dictionary == this) 
     { 
      result = value; 
      return true; 
     } 
     return this.TryLookup(value.Value, out result); 
    } 

    bool IXmlDictionary.TryLookup(int key, out XmlDictionaryString result) 
    { 
     string res; 
     if (!values.TryGetValue(key, out res)) 
     { 
      result = null; 
      return false; 
     } 
     result = new XmlDictionaryString(this, res, key); 
     return true; 
    } 

    public bool /* IXmlDictionary. */ TryLookup(string value, out XmlDictionaryString result) 
    { 
     int key; 
     if (!keys.TryGetValue(value, out key)) 
     { 
      result = null; 
      return false; 
     } 

     result = new XmlDictionaryString(this, value, key); 
     return true; 
    } 
} 

結果是 - 我TryLookup方法被稱爲OK,但是DataContractSerializer.WriteObject產生一個空文件。

如何使用預共享字典?

在此先感謝!

P.S.我不想弄亂XmlBinaryReaderSession/XmlBinaryWriterSession:我沒有「會話」,而是一次有很多線程訪問10 GB +數據庫。我想要的只是靜態預定義字典。

更新:好吧我已經想通了,我只需要調用「XmlDictionaryWriter.Flush」。剩下的唯一問題是 - 爲什麼系統提供的IXmlDictionary實現不按預期工作?

回答

0

爲XmlDictionaryWriter你需要使用會話。
example

private static Stream SerializeBinaryWithDictionary(Person person,DataContractSerializer serializer) 
    { 
     var stream = new MemoryStream(); 
     var dictionary = new XmlDictionary(); 
     var session = new XmlBinaryWriterSession(); 
     var key = 0; 
     session.TryAdd(dictionary.Add("FirstName"), out key); 
     session.TryAdd(dictionary.Add("LastName"), out key); 
     session.TryAdd(dictionary.Add("Birthday"), out key); 
     session.TryAdd(dictionary.Add("Person"), out key); 
     session.TryAdd(dictionary.Add("http://www.friseton.com/Name/2010/06"),out key); 
     session.TryAdd(dictionary.Add("http://www.w3.org/2001/XMLSchema-instance"),out key); 

     var writer = XmlDictionaryWriter.CreateBinaryWriter(stream, dictionary, session); 
     serializer.WriteObject(writer, person); 
     writer.Flush(); 
     return stream; 
    } 
0

唯一的辦法,我的方法能複製與不使用IXmlDictionary的問題是,當我的課,卻並不具備DataContract屬性來修飾。以下應用程序顯示裝飾類和未修飾類的尺寸差異。

using System; 
using System.Runtime.Serialization; 
using System.Xml; 

namespace XmlPresharedDictionary 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Serialized sizes"); 
      Console.WriteLine("-------------------------"); 
      TestSerialization<MyXmlClassUndecorated>("Undecorated: "); 
      TestSerialization<MyXmlClassDecorated>("Decorated: "); 
      Console.ReadLine(); 
     } 

     private static void TestSerialization<T>(string lineComment) where T : new() 
     { 
      XmlDictionary xmlDict = new XmlDictionary(); 
      xmlDict.Add("MyElementName1"); 

      DataContractSerializer serializer = new DataContractSerializer(typeof(T)); 

      using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) 
      using (var writer = XmlDictionaryWriter.CreateBinaryWriter(stream, xmlDict)) 
      { 
       serializer.WriteObject(writer, new T()); 
       writer.Flush(); 
       Console.WriteLine(lineComment + stream.Length.ToString()); 
      } 
     } 
    } 

    //[DataContract] 
    public class MyXmlClassUndecorated 
    { 
     public MyElementName1[] MyElementName1 { get; set; } 

     public MyXmlClassUndecorated() 
     { 
      MyElementName1 = new MyElementName1[] { new MyElementName1("A A A A A"), new MyElementName1("A A A A A") }; 
     } 
    } 

    [DataContract] 
    public class MyXmlClassDecorated 
    { 
     public MyElementName1[] MyElementName1 { get; set; } 

     public MyXmlClassDecorated() 
     { 
      MyElementName1 = new MyElementName1[] { new MyElementName1("A A A A A"), new MyElementName1("A A A A A") }; 
     } 
    } 

    [DataContract] 
    public class MyElementName1 
    { 
     [DataMember] 
     public string Value { get; set; } 

     public MyElementName1(string value) { Value = value; } 
    } 
}