1

当用户离开托管应用程序的页面时,我使用 Silverlight 3 中的 IsolatedStorage 来存储一些设置。

目前我正在使用 DataContractSerializer 将设置写入文件。在某些情况下,生成的文件非常大,超过 10MB(这个大小很大一部分是由于序列化程序本身和它生成的 XML)。这会产生问题,因为

  • 我必须向用户请求额外的空间
  • 将数据写入文件真的很慢

任何人都可以分享他们用于处理隔离存储中较大文件的一些策略吗?

  • 您如何确定可能需要的磁盘空间量?
  • 您是否使用 DataContract 或 Xml 序列化程序,然后在保存之前压缩结果?
  • 还是您使用某种二进制/自定义序列化?如果是这样,您是否节省了大量空间或时间?
  • 是否有某种方式可以声明您的应用程序需要一定的配额,以便不必在某个任意点提示用户?

我个人不喜欢像这样将大量数据写入文件,但在向产品经理解释问题并说服他们更改要求之前,我需要了解所有可用选项。

谢谢!

4

5 回答 5

4

猛男,

您可能需要考虑改用 XMLSerializer。这是我随着时间的推移确定的:

XMLSerializer 和 DataContractSerializer 类提供了一种将对象图序列化和反序列化到 XML 和从 XML 反序列化的简单方法。

主要区别在于:
1.
如果您使用 [XmlAttribute] 而不是 [XmlElement],则 XMLSerializer 的负载比 DCS 小得多
DCS 始终将值存储为元素
2.
DCS 是“选择加入”而不是“选择退出”
使用 DCS,您使用 [DataMember] 显式标记要序列化的内容
使用 DCS,您可以序列化任何字段或属性,即使它们被标记为受保护或私有
使用 DCS,您可以使用 [IgnoreDataMember] 让序列化程序忽略某些属性
使用 XMLSerializer 对公共属性进行序列化,并且需要对设置器进行反序列化
使用 XmlSerializer 您可以使用 [XmlIgnore] 让序列化程序忽略公共属性
3.请
注意!DCS.ReadObject 在反序列化期间不调用构造函数 如果
您需要执行初始化,DCS 支持以下回调挂钩:
[OnDeserializing]、[OnDeserialized]、[OnSerializing]、[OnSerialized]
(也可用于处理版本控制问题)

能够在两个序列化程序之间切换,您可以同时使用两组属性,如下所示:

[DataContract]
[XmlRoot]
    public class ProfilePerson : NotifyPropertyChanges
    {
[XmlAttribute]
[DataMember]
        public string FirstName { get { return m_FirstName; } set { SetProperty(ref m_FirstName, value); } }
        private string m_FirstName;
[XmlElement]
[DataMember]
        public PersonLocation Location { get { return m_Location; } set { SetProperty(ref m_Location, value); } }
        private PersonLocation m_Location = new PersonLocation(); // Should change over time
[XmlIgnore]
[IgnoreDataMember]
        public Profile ParentProfile { get { return m_ParentProfile; } set { SetProperty(ref m_ParentProfile, value); } }
        private Profile m_ParentProfile = null;

        public ProfilePerson()
        {
        }
    }

另外,查看我的可以在两者之间切换的 Serializer 类:

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

namespace ClassLibrary
{
    // Instantiate this class to serialize objects using either XmlSerializer or DataContractSerializer
    internal class Serializer
    {
        private readonly bool m_bDCS;

        internal Serializer(bool bDCS)
        {
            m_bDCS = bDCS;
        }

        internal TT Deserialize<TT>(string input)
        {
            MemoryStream stream = new MemoryStream(input.ToByteArray());
            if (m_bDCS)
            {
                DataContractSerializer dc = new DataContractSerializer(typeof(TT));
                return (TT)dc.ReadObject(stream);
            }
            else
            {
                XmlSerializer xs = new XmlSerializer(typeof(TT));
                return (TT)xs.Deserialize(stream);
            }
        }

        internal string Serialize<TT>(object obj)
        {
            MemoryStream stream = new MemoryStream();
            if (m_bDCS)
            {
                DataContractSerializer dc = new DataContractSerializer(typeof(TT));
                dc.WriteObject(stream, obj);
            }
            else
            {
                XmlSerializer xs = new XmlSerializer(typeof(TT));
                xs.Serialize(stream, obj);
            }

            // be aware that the Unicode Byte-Order Mark will be at the front of the string
            return stream.ToArray().ToUtfString();
        }

        internal string SerializeToString<TT>(object obj)
        {
            StringBuilder builder = new StringBuilder();
            XmlWriter xmlWriter = XmlWriter.Create(builder);
            if (m_bDCS)
            {
                DataContractSerializer dc = new DataContractSerializer(typeof(TT));
                dc.WriteObject(xmlWriter, obj);
            }
            else
            {
                XmlSerializer xs = new XmlSerializer(typeof(TT));
                xs.Serialize(xmlWriter, obj);
            }

            string xml = builder.ToString();
            xml = RegexHelper.ReplacePattern(xml, RegexHelper.WildcardToPattern("<?xml*>", WildcardSearch.Anywhere), string.Empty);
            xml = RegexHelper.ReplacePattern(xml, RegexHelper.WildcardToPattern(" xmlns:*\"*\"", WildcardSearch.Anywhere), string.Empty);
            xml = xml.Replace(Environment.NewLine + "  ", string.Empty);
            xml = xml.Replace(Environment.NewLine, string.Empty);
            return xml;
        }
    }
}

祝你好运,
吉姆·麦柯迪

面对面软件阴阳钱

于 2010-02-01T16:56:55.457 回答
1

另一种选择是压缩 xml 序列化的内容。我们还有一个大型序列化,其粗略的压缩比为 10:1。当然,压缩可能需要相当多的 CPU 来发挥它的魔力。我们在线程中生成压缩以确保用户界面不会变慢。我们正在使用在 Silverlight 下工作的修改后的 SharpZipLib。

于 2010-02-01T17:02:17.657 回答
1

另一种选择是序列化为 json。我不知道性能,但我只是比较了将相当复杂的实体列表序列化为 json 与 xml 时的输出,而 json 更紧凑。使用 json 得到的字符串是 1301303 字节。使用 xml,2429630。所以它几乎是使用 json 的一半大小。

下面是我在序列化/反序列化为 json 时使用的辅助类。

编辑
我做了一些性能测试,结果发现 json 也更快。使用 xml,序列化 10000 个对象需要 636 毫秒,而 json 只有 257。有人知道是否有理由不选择 json 而不是 xml?

编辑
再次测试,这次使用真实数据:
(1000 个对象)
未压缩 json:605 kb
未压缩 xml:3,53 MB(!)
压缩 json:28,5 kb
压缩 xml:69,9 kb
使用预初始化序列化程序时的性能:
json: ~350 ms
xml: ~120 ms

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Text;
using System.Runtime.Serialization.Json;

namespace GLS.Gui.Helper
{
    public static class SerializationHelper
    {
        public static string SerializeToJsonString(object objectToSerialize)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(objectToSerialize.GetType());
                serializer.WriteObject(ms, objectToSerialize);
                ms.Position = 0;

                using (StreamReader reader = new StreamReader(ms))
                {
                    return reader.ReadToEnd();
                }
            }
        }
        public static T Deserialize<T>(string jsonString)
        {
            using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));

                return (T)serializer.ReadObject(ms);
            }
        }

    }
}
于 2010-02-02T08:59:03.587 回答
1

我有一个用于 Silverlight 和 .NET 的紧凑型二进制序列化程序类,它创建了对象图的相当紧凑的表示形式——我必须出于同样的原因构建它(以及通过线路将内容发送到我的 WCF 服务的成本)。

你可以在我的博客上找到代码和进一步的描述。

于 2010-09-15T10:32:56.777 回答
0

另一个开源序列化器是SharpSerializer。它甚至可以将非常复杂的结构序列化为二进制格式。无需事先用属性标记它们。此外,它可以将数据序列化为 Xml,即用于调试。

于 2011-08-07T06:50:49.917 回答