【问题标题】:.NET binary XML with pre-shared dictionary.NET 二进制 XML 与预共享字典
【发布时间】:2011-07-15 06:07:55
【问题描述】:

我正在使用 XmlDictionaryWriter 将对象序列化到带有数据协定序列化程序的数据库中。 效果很好,大小和速度都比使用 text/xml 好 2 倍。

但是,我将不得不处理我的数据库中的大量记录,其中任何额外的字节都会直接转换为数据库大小的千兆字节。 这就是为什么我想通过使用 XML 字典来进一步减小大小。

我该怎么做?

我看到 XmlDictionaryWriter.CreateBinaryWriter 静态方法接受 IXmlDictionary 类型的第二个参数。 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 方法调用正常,但是 DataContractSerializer.WriteObject 生成一个空文档。

如何使用预共享字典?

提前致谢!

附:我不想弄乱 XmlBinaryReaderSession/XmlBinaryWriterSession:我没有“会话”,而是有一个 10 GB 以上的数据库,可以同时被多个线程访问。我想要的只是静态预定义字典。

更新:好的,我发现我只需要调用“XmlDictionaryWriter.Flush”。剩下的唯一问题是 - 为什么系统提供的 IXmlDictionary 实现没有按预期工作?

【问题讨论】:

    标签: c# .net .net-4.0 c#-4.0 datacontractserializer


    【解决方案1】:

    对于 XmlDictionaryWriter,您需要使用 session。
    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;
        }
    

    【讨论】:

      【解决方案2】:

      我能够复制没有使用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; }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-05
        • 1970-01-01
        • 1970-01-01
        • 2018-05-15
        • 1970-01-01
        • 2014-03-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多