序列化实现持久化_通过序列化实现持久性

序列化实现持久化

摘要:
(Summary:
)

持久性是应用程序存储对象状态并在必要时恢复它的能力。 本文在数据访问,可读性和运行时成本方面比较了两种常见的序列化类型。 提供了使用 BinaryFormatter with simple encryption is provided.

介绍:
(Introduction:
)

第一次阅读有关序列化的dotnet文档时,我感到很惊讶。 在dotnet时代之前,处理配置数据是一个很大的麻烦。 您将不得不编写大型代码段以将数据流式传输到文件中,然后再次解析长字符串以找出正确的数据以供回读。 在进行序列化时,我希望创建一个完整的应用程序缓存并还原它,就像当今的Windows系统“Hibernate”功能一样。 尽管现实总是遥不可及,但点网序列化在缓存应用程序的“一部分”(即数据对象)方面仍然非常有用。

Dotnet framework provides two types of serialization: shallow serialization, and deep serialization, represented by

Dotnet框架提供两种类型的序列化:浅层序列化和深层序列化,分别由

XmlSerializer

in System.Xml.Serialization namespace and

System.Xml.Serialization命名空间中

BinaryFormatter

in System.Runtime.Serialization.Formatters.Binary namespace,

System.Runtime.Serializati中 on.Formatt 二进制 命名空间

respectively. The differences between the two types are obvious: the former is designed to save and load objects in human-readable XML format, and the latter provides compact binary encoding either for storage or for network streaming. The dotnet framework also includes the abstract FORMATTERS class that can be used as a base class for custom formatters. We will focus on XmlSerializer and BinaryFormatter in this article.

分别。 两种类型之间的区别是显而易见的:前者旨在以人类可读的XML格式保存和加载对象,而后者则提供用于存储或网络流的紧凑二进制编码。 dotnet框架还包括抽象的FORMATTERS类,该类可用作自定义格式程序的基类。 在本文中,我们将重点介绍

XmlSerializer基础
(XmlSerializer Basics
)

附件包中包含三个项目。 第一个XMLSerializerSample显示了可以应用 XmlSerializer could be applied. In file SampleClasses.cs, three sample classes are defined: BuildinType contains properties with primary types; DerivedClass uses build-in reference types, also demonstrates a class with base class; CollectionTypes declares several different build-in Collection types.

The Main program routine simply serializes out the instance of each class to a file and reads it back sequentially, plus an array object to test the performance on bulk data. I tag the test case numbers in both the source code and the article.  You can perform the tests yourself if you'd like.  Simple guidelines are in the source code, which illustrate the basic elements of a Software Test Document (STD).

Main程序例程简单地将每个类的实例序列化到文件中,并依次读取它,再加上一个数组对象以测试大容量数据的性能。 我在源代码和文章中都标记了测试用例编号。 如果需要,您可以自己执行测试。 源代码中包含简单的准则,这些准则说明了软件测试文档(STD)的基本元素。

The output of the program is like:

该程序的输出类似于:

test2.xml (Test Case 1):
<?xml version="1.0"?>
<DerivedClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <InstanceID>2</InstanceID>
  <Number>300.900024</Number>
  <Description>This is a test.</Description>
  <TestState>DONE</TestState>
  <TestTime>2010-12-08T02:23:50.265625+08:00</TestTime>
  <StrFont>Times New Roman, 10pt</StrFont>
</DerivedClass>
XmlSerializer supports:

All the primary types (Test Case 2);

所有主要类型(测试用例2);



Derived class (Test Case 3);

派生类(测试用例3);



Simple collection types such as array, list (Test Case 4);

简单的集合类型,例如数组,列表(测试用例4);



Public data members – only (Test Case 5).

仅限公共数据成员-(测试案例5)。



Most build-in reference types are not serializable (Test Case 6);

大多数内置引用类型不可序列化(测试用例6);



Static data member won’t get serialized (Test Case 7);

静态数据成员不会序列化(测试用例7);



Private fields can not be saved (Test Case 5);

私有字段无法保存(测试用例5);



There must be a default constructor. Normally the complier will generate one if none explicit constructor is present. But sometimes we could create a parameterized constructor but forget to add a default constructor. Then the serialization would be “accidentally” disabled. (Test Case 8);

必须有一个默认的构造函数。 通常,如果没有显式构造函数,编译器将生成一个。 但是有时我们可以创建一个参数化的构造函数,但是忘记添加默认构造函数。 然后将“意外”禁用序列化。 (测试用例8);



String manipulation is very expensive, and storage in text format is huge (Test Case 9):

字符串操作非常昂贵,并且文本格式的存储量很大(测试用例9):



Execution time and output file size

Font thisFont = new Font("Times New Roman", 10F); [XmlIgnore] public Font ThisFont //Accessors for general calling. { get { return thisFont; } set { thisFont = value; } } public string StrFont //Accessors for serialization. { get { return Utility.ObjectToString(thisFont); } set { thisFont = (Font)Utility.ObjectFromString(typeof(Font), value); } }

字体thisFont = new字体(“ Times New Roman”,10F); [XmlIgnore] public字体ThisFont //用于一般调用的访问器。 {得到{返回thisFont; }设置{thisFont = value; }} public string StrFont //用于序列化的访问器。 {get {return Utility.ObjectToString(thisFont); } set {thisFont =(Font)Utility.ObjectFromString(typeof(Font),value); }}

XmlSerializer is the human-readable format of the output. If you have a relatively simple object and need to modify the data directly, XmlSerializer is a good choice.

BinaryFormatter基础
(BinaryFormatter Basics
)

附加软件包中的第二个项目与第一个项目相似,但有一些小的更改:

    1.  The use of XmlSerializer is substituted with BinaryFormatter;

1.将XmlSerializer的使用替换为BinaryFormatter;

    2.  The attribute “[Serializable]” is added ahead of each class;

2.在每个类的前面添加“ [可序列化]”属性;

    3.  A build-in graphic type “Brush” is added to the DerivedClass;

3.将内置图形类型“画笔”添加到DerivedClass;

The same tests are performed on the classes described above. The advantages of BinaryFormatter are:

对上述类执行相同的测试。

All the public and private fields in an object are capable to be serialized (Test Case 11);

对象中的所有公共和私有字段都可以序列化(测试用例11);



No need to declare the default constructor any more. (Test Case 12) But it’s always a good practice to generate a default constructor along with the parameterized one;

无需再声明默认构造函数。 (测试用例12)但是,始终将默认构造函数与参数化构造函数一起生成是一种很好的做法。



Almost all build-in types are supported with a few exceptions such as graphic objects, with which the Serializable attribute is not defined. (Test Case 14)

几乎所有的内置类型都受支持,但一些例外情况(例如图形对象)并未定义Serializable属性。 (测试用例14)



Static field is not serializable, because it’s non-object referenced (it’s not part of the object), as shown in the follow picture (Test Case 15).

静态字段不可序列化,因为它是非对象引用的(它不是对象的一部分),如下图所示(测试案例15)。



Static fields not serialized
do want static members to be serializable, you can implement ISerializable interface to manually add the information and retrieve it back (Test Case 16):

[Serializable] public class BuildinType: ISerializable { static int instanceCount = 0; public BuildinType(SerializationInfo info, StreamingContext context) { BuildinType.instanceCount = info.GetInt32("instanceCount"); } public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("instanceCount", instanceCount, typeof(int)); } Now the value of instanceCount is persistent.

[可序列化]公共类BuildinType:ISerializable {static int instanceCount = 0; 公共BuildinType(SerializationInfo info,StreamingContext上下文){BuildinType.instanceCount = info.GetInt32(“ instanceCount”); } public void GetObjectData(SerializationInfo info,StreamingContext context){info.AddValue(“ instanceCount”,instanceCount,typeof(int)); 现在,instanceCount的值是持久的。



Implement ISerializable to serialize static member

Binary operation is much faster than string operation (Test Case 16):

二进制运算比字符串运算快得多(测试用例16):



Execution time and output file size

The Dictionary type is also supported, with a little more cost (Test Case 17).

还支持Dictionary类型,但要多花一点钱(测试用例17)。



A little slower to serialize Dictionary type

Basically, you don’t need to worry too much about your data types, just put SerializableAttribute on your class. Then you can achieve persistency by saving the object wherever it needs to. For the types that can not be persisted properly, you can either put NonSerializedAttribute on the data member for the serializer to ignore it, or implement ISerializable interface to make it serializable.

基本上,您不需要太担心数据类型,只需将

使用例
(Example of use
)

从以上实验中,我们可以看到,相对于 BinaryFormatter over XmlSerializer. Even for configuration settings, it is recommend to modify the data through user interface, rather than directly touching the data in the output files. The third project in the attached package provides two more helper function to save and load data without encryption.
public static void TSerialize(object theObject, string sFileName)
        {
            BinaryFormatter btFormatter = new BinaryFormatter();
            FileStream theFileStream = new FileStream(sFileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
            btFormatter.Serialize(theFileStream, theObject);
            theFileStream.Close();
        }

        public static object TDeSerialize(Type theType, string sFileName)
        {
            if (sFileName == null || sFileName == "" || !File.Exists(sFileName))
            {
                return null;
            }
            FileStream theFileStream = new FileStream(sFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            BinaryFormatter btFormatter = new BinaryFormatter();
            object theObj = btFormatter.Deserialize(theFileStream);
            theFileStream.Close();
            return theObj;
        }
public static void SerializeWithEncrypt(object theObject, string sFileName)
        {
            MemoryStream theMS = new MemoryStream();
            BinaryFormatter btFormatter = new BinaryFormatter();
            btFormatter.Serialize(theMS, theObject);
            theMS.Seek(0, SeekOrigin.Begin);
            byte[] temp = theMS.ToArray();

            temp = Encrypt(temp);
            //Output to a file.
            FileStream theFileStream = new FileStream(sFileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
            BinaryWriter theBW = new BinaryWriter(theFileStream);

            theBW.Write(temp, 0, temp.Length);
            theBW.Close();
            theFileStream.Close();
            theMS.Dispose();
        }

        public static object DeSerializeWithDecrypt(string sFileName)
        {
            if (sFileName == null || sFileName == "" || !File.Exists(sFileName))
            {
                return null;
            }

            byte[] temp = File.ReadAllBytes(sFileName);

            temp = Decrypt(temp);

            MemoryStream theMS = new MemoryStream(temp);
            BinaryFormatter btFormatter = new BinaryFormatter();
            object theObj = btFormatter.Deserialize(theMS);
            theMS.Dispose();
            return theObj;
        }
[Serializable]
    public sealed class Configuration
    {
        private static Configuration instance = null;

        private Configuration()
        {
        }

        public static Configuration Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = (Configuration)Utility.TDeSerialize("test.dat");
                }
                if (instance == null)
                {
                    instance = new Configuration();
                }
                return instance;
            }
        }
…
…

Another attached application, TCPaint, uses exactly the same code to persist the size and location of the form as well as other configuration setting data such as MRU (most recent used files). The unlimited steps of undo and redo actions are also saved using this technique. A user can always rewind and modify their drawings as a set of individual objects rather than as a bitmap image.

另一个附加应用程序TCPaint使用完全相同的代码来保留表单的大小和位置以及其他配置设置数据(例如MRU(最近使用的文件))。 使用此技术还可以保存无限的撤消和重做操作步骤。 用户始终可以将其图形作为一组单独的对象而不是位图图像进行倒带和修改。

In the end, using serialization properly can save you a lot time and headaches.

最后,正确使用序列化可以节省大量时间和头痛。

TSerializerSample.zip TSerializerSample.zip TCPaint.zip TCPaint.zip

翻译自: https://www.experts-exchange.com/articles/4275/Achieve-Persistence-Through-Serialization.html

序列化实现持久化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值