Silverlight IsolatedStorage методы для больших файлов? - PullRequest
1 голос
/ 01 февраля 2010

Я использую IsolatedStorage в Silverlight 3 для хранения некоторых настроек, когда пользователь уходит со страницы, на которой размещено приложение.

В настоящее время я использую DataContractSerializer для записи настроек в файл. В некоторых случаях результирующий файл имеет довольно большой размер, более 10 МБ (большая часть этого размера связана с самим сериализатором и сгенерированным им XML). Это создает проблемы, потому что

  • я должен запросить дополнительное пространство у пользователя
  • запись данных в файл очень медленная

Кто-нибудь может поделиться некоторыми стратегиями, которые они использовали для работы с большими файлами в IsolatedStorage?

  • как определить вероятный объем дискового пространства, который вам потребуется?
  • используете ли вы DataContract или Xml Serializer, а затем архивируете результат перед сохранением?
  • или вы используете какую-то двоичную / пользовательскую сериализацию? Если да, удалось ли вам сэкономить много места или времени?
  • существует ли какой-либо способ декларативно заявить, что вашему приложению требуется определенная квота, чтобы пользователю не приходилось запрашивать в какой-то произвольный момент?

Мне лично не нравится записывать большие объемы данных в файл, подобный этому, но мне нужно знать все доступные варианты, прежде чем я объясню проблемы менеджеру продукта и убедлю их изменить требования.

Спасибо!

Ответы [ 5 ]

4 голосов
/ 01 февраля 2010

slugster,

Возможно, вы захотите вместо этого перейти на XMLSerializer. Вот что я определил со временем:

Классы XMLSerializer и DataContractSerializer предоставляют простые средства сериализации и десериализации графов объектов в и из XML.

Ключевые отличия:
1.
XMLSerializer имеет гораздо меньшую полезную нагрузку, чем DCS, если вы используете [XmlAttribute] вместо [XmlElement]
DCS всегда хранит значения как элементы
2.
DCS является «opt-in», а не «opt-out»
В 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 Software и YinYangMoney

1 голос
/ 15 сентября 2010

У меня есть класс компактного двоичного сериализатора для Silverlight и .NET, который создает достаточно компактные представления графа объектов - мне пришлось построить его по той же причине (и стоимости отправки материала по проводам в мою службу WCF).

Вы можете найти код и дальнейшее описание в моем блоге .

1 голос
/ 02 февраля 2010

Другим вариантом является сериализация в JSON. Я не знаю о производительности, но Я только что сравнил вывод при сериализации довольно сложного списка сущностей с json против xml, и json гораздо более компактен. Используя json, полученная строка была 1301303 байта. С xml 2429630. Таким образом, это почти вдвое меньше, чем при использовании json.

Ниже приведен класс помощника, который я использую при сериализации / десериализации в json.

EDIT
Я провел некоторое тестирование производительности, и на самом деле оказалось, что json также быстрее. В xml сериализация 10000 объектов заняла 636 миллисекунд, а в json - только 257. Кто-нибудь знает, есть ли причины не выбирать json вместо xml?

EDIT
Проверено снова, на этот раз с реальными данными:
(1000 предметов)
Несжатый JSON: 605 КБ
Несжатый xml: 3,53 МБ (!)
Молнии json: 28,5 кб
Молния xml: 69,9 кб
Производительность при использовании предварительно инициализированного сериализатора:
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);
            }
        }

    }
}
1 голос
/ 01 февраля 2010

Другой альтернативой является сжатие содержимого сериализации xml. У нас также есть большая сериализация, которая имеет грубую степень сжатия 10: 1. Конечно, сжатие может занять немало ресурсов процессора, чтобы сделать свое волшебство. Мы создаем сжатие в потоке, чтобы убедиться, что пользовательский интерфейс не замедляется. Мы используем модифицированную SharpZipLib, которая работает под Silverlight.

0 голосов
/ 07 августа 2011

Другой сериализатор с открытым исходным кодом - SharpSerializer . Он может сериализовать даже очень сложные структуры в двоичный формат. Нет необходимости отмечать их ранее атрибутами. Кроме того, он может сериализовать данные в XML, т.е. для отладки.

...