适用于较大文件的 SilverlightisolatedStorage 技术?

发布于 2024-08-20 08:00:05 字数 561 浏览 7 评论 0原文

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

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

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

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

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

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

谢谢!

I am using IsolatedStorage in Silverlight 3 to store some settings when a user navigates away from a page hosting the application.

Currently i'm using a DataContractSerializer to write the settings to file. In some circumstances the resulting file is quite large, over 10MB (a lot of this size is due to the serializer itself and the XML it generates). This produces problems because

  • i have to request the extra space from the user
  • it is really slow writing the data to file

can anyone share some strategies they have used for dealing with larger files in IsolatedStorage?

  • how do you determine the likely amount of disk space you will need?
  • do you use a DataContract or Xml Serializer and then zip the result before saving?
  • or do you use some sort of binary/custom serialization? If so, did you gain any substantial space or time savings?
  • is there some way of declaratively saying your application requires a certain quota, so that the user doesn't have to be prompted at some arbitrary point?

I personally don't like writing large quantities of data to file like this, but i need to know all the available options before i explain the issues to a product manager and persuade them to change the requirements.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

鲸落 2024-08-27 08:00:05

slugster,

您可能需要考虑改用 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()
        {
        }
    }

另外,请查看我的可以在两者之间切换的序列化器类:

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;
        }
    }
}

祝您好运,
Jim McCurdy

Face To Face SoftwareYinYangMoney

slugster,

You may want to consider switching over to XMLSerializer instead. Here is what I have determined over time:

The XMLSerializer and DataContractSerializer classes provides a simple means of serializing and deserializing object graphs to and from XML.

The key differences are:
1.
XMLSerializer has much smaller payload than DCS if you use [XmlAttribute] instead of [XmlElement]
DCS always store values as elements
2.
DCS is "opt-in" rather than "opt-out"
With DCS you explicitly mark what you want to serialize with [DataMember]
With DCS you can serialize any field or property, even if they are marked protected or private
With DCS you can use [IgnoreDataMember] to have the serializer ignore certain properties
With XMLSerializer public properties are serialized, and need setters to be deserialized
With XmlSerializer you can use [XmlIgnore] to have the serializer ignore public properties
3.
BE AWARE! DCS.ReadObject DOES NOT call constructors during deserialization
If you need to perform initialization, DCS supports the following callback hooks:
[OnDeserializing], [OnDeserialized], [OnSerializing], [OnSerialized]
(also useful for handling versioning issues)

If you want the ability to switch between the two serializers, you can use both sets of attributes simultaneously, as in:

[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()
        {
        }
    }

Also, check out my Serializer class that can switch between the two:

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;
        }
    }
}

Good Luck,
Jim McCurdy

Face To Face Software and YinYangMoney

青衫儰鉨ミ守葔 2024-08-27 08:00:05

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

Another alternative is to zip the contents of the xml serialization. We also have a large serialization that has a rough compression ratio of 10-to-1. Of course the compression can take a fair bit of CPU to do its magic. We spawn of the compression in a thread to make sure the user interface doesn't slow down. We are using a modified SharpZipLib that works under Silverlight.

饮惑 2024-08-27 08:00:05

另一种选择是序列化为 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 毫秒
xml:~120 毫秒

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);
            }
        }

    }
}

Another option is to serialize to json. I do not know about performance, but I just compared the output when serializing a fairly complex list of entities to json vs. xml, and json is much more compact. Using json the resulting string was 1301303 bytes. With xml, 2429630. So it's almost half the size using json.

Below is the helper class I use when serializing/deserializing to json.

EDIT
I did some performance testing, and it actually turns out that json is faster as well. With xml, serializing 10000 objects took 636 milliseconds, with json only 257. Does anybody know if there are reasons not to choose json over xml?

EDIT
Tested again, with real data this time:
(1000 objects)
Uncompressed json: 605 kb
Uncompressed xml: 3,53 MB (!)
Zipped json: 28,5 kb
Zipped xml: 69,9 kb
Performance when using pre-initialized serializer:
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);
            }
        }

    }
}
浅唱ヾ落雨殇 2024-08-27 08:00:05

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

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

I have a compact binary serializer class for Silverlight and .NET that creates reasonably compact representations of an object graph - I had to build it for the same reason (and the cost of sending stuff over the wire to my WCF service).

You can find the code and a further description on my blog.

守不住的情 2024-08-27 08:00:05

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

Another open source serializer is SharpSerializer. It can serialize even very complicated structures to binary format. There is no need to mark them prior with attributes. Additionally it can serialize the data to Xml, i.e. for debugging.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文