Silverlight隔离存储大文件的技术?

时间:2010-02-01 13:07:50

标签: silverlight silverlight-3.0 isolatedstorage isolatedstoragefile

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

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

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

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

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

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

谢谢!

5 个答案:

答案 0 :(得分:4)

slugster,

您可能需要考虑切换到XMLSerializer。以下是我随着时间的推移所确定的:

XMLSerializer和DataContractSerializer类提供了一种简单的方法,可以将对象图与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;
        }
    }
}
祝你好运,
吉姆麦克库迪

Face To Face SoftwareYinYangMoney

答案 1 :(得分:1)

另一种方法是压缩xml序列化的内容。我们还有一个大型序列化,其压缩比为10比1。当然压缩可以花费相当多的CPU来实现其魔力。我们在一个线程中产生压缩,以确保用户界面不会减慢速度。我们正在使用在Silverlight下运行的修改后的SharpZipLib。

答案 2 :(得分: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);
            }
        }

    }
}

答案 3 :(得分:1)

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

您可以在我的blog找到代码和进一步说明。

答案 4 :(得分:0)

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