C#序列化链表

场景简化:
    程序中的数据每隔1s实时获得的,存储到链表里,需要及时保存到文件里去。
    之前的方法是把链表对象序列化到文件里去,好处是不需要太多处理,不用管链表中是否有元素(相对于后面的第三种方法而言)。可是这样有个问题,每次都得把整个链表序列化到文件里去,当数据多了之后开销挺大的。直觉上应该是每次只把新增的数据追加到文件里就可以了。

  为了简洁起见,把异常处理,局部变量声明等的都去了。每次只贴出修改过的类的代码,MeasuredValue是一个类,存储了采集到的数据。

  第一版的代码如下:

 1 public static class FileSerializer
 2  {
 3         //stream是调用者负责关闭的
 4         public static void Serialize(FileStream stream, object objectToSerialize)
 5         {
 6                 BinaryFormatter bFormatter = new BinaryFormatter();
 7                 bFormatter.Serialize(stream, objectToSerialize);
 8         }
 9         public static T Deserialize<T>(FileStream stream)
10         {
11             T objectToDeSerialize = default(T);
12             BinaryFormatter bFormatter = new BinaryFormatter();
13             objectToDeSerialize = (T)bFormatter.Deserialize(stream);
14             return objectToDeSerialize;
15         }
16 }
17  class Serialize
18 {
19         public bool SerializeMeasuredData(List<MeasuredValue> values){
20             SerializeHelper data = new SerializeHelper(values);
21             FileSerializer.Serialize(stream, data);
22         }
23         public bool DeSerializeMeasuredData(List<MeasuredValue> values)
24         {
25                 SerializeHelper data = null;
26                 stream = File.Open(_fileName, FileMode.Open, FileAccess.Read);
27                 data = FileSerializer.Deserialize<SerializeHelper>(stream);
28                 values = data;
29         }
30
31}
32     //33     //想在序列化时,序列化某些指定的List,并添加了别的信息所以加了这个SerializeHelper。
34 class SerializeHelper(){
35         List<MeasuredValue> _values;
36         public SerializeHelper(List<MeasuredValue> values){
37             _values = values;
38         }
39         public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
40         {
41             info.AddValue("VALUES", _values, typeof(List<MeasuredValue>));
42         }
43         private SerializeHelper(SerializationInfo info, StreamingContext context)
44         {
45             _values = (List<MeasuredValue>)info.GetValue(_values, typeof(List<MeasuredValue>));
46         }
47
48 }

  后来想实现每次只把增加的采集数据序列化到文件里。我不确定思路对不对,所以使用快猛糙的方法先实现了一下。

  第二版代码如下:

 1 class Serialize
 2     {
 3         uint _id;
 4         public bool SerializeMeasuredData(List<MeasuredValue> values){
 5             SerializeHelper data = new SerializeHelper(values, _id);
 6             _id++;
 7             FileSerializer.Serialize(stream, data);
 8         }
 9         public bool DeSerializeMeasuredData(List<MeasuredValue> values)
10         {
11                 SerializeHelper data = null;
12                 stream = File.Open(_fileName, FileMode.Open, FileAccess.Read);
13                 data = FileSerializer.Deserialize<SerializeHelper>(stream);
14                 values = data;
15         }
16     }
17    18
19 class SerializeHelper(){
20         List<MeasuredValue> _values;
21         _id;
22         public SerializeHelper(List<MeasuredValue> values, uint id){
23             _values = values;
24             _id = id;
25         }
26
27         public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
28         {
29             info.AddValue("VALUES"+_id.ToString(), _values[_values.Length-1], typeof(MeasuredValue));
30         }
31         //反序列化时id却由SerializeHelper来维护,因为不可能通过参数传递过来
32         private SerializeHelper(SerializationInfo info, StreamingContext context)
33         {
34             _id = 0;
35             MeasuredValue mv= null;
36             _values = new List<MeasuredValue>();
37             try{
38                 while(true){
39                     mv = (MeasuredValue)info.GetValue("VALUES"+id.ToString(), typeof(MeasuredValue));
40                     _values.Add(mv);
41                 }
42             }
43             catch(Exception ex){//出现异常说明到文件末尾
44
45             }
46         }
47 }

  可是测试时出错了,不能正常序列化出链表。各位可以猜到我的问题出在哪里吗?

  调式时发现SerializeHelper(SerializationInfo info, StreamingContext context)这个函数中的info变量里,MemberCount值为1, MemberNames[4]中只有MemberNames[0]不会空,是"VALUES0",这样就惨了,说明 SerializeHelper里反序列化和序列化时是对应的。由于序列化时是只写入了一个MeasuredValue,所以反序列化时,只能获得一个MeasuredValue,所以生成链表的操作不能在这个类里进行。对于SerializationInfo.AddValue(String name, object value, Type, type)时的name这个参数的作用,我很是疑惑,看样子这个name不是全局范围的标识符,在上面的例子中,是仅在代表一个SerializeHelper的字节流中起标识符的作用?
    本来感觉挺麻烦的,按照我一贯直来直往的思路,需要把List一部分一部分的序列化,之前就搜过,没啥资料,而且我也不知道该怎么组织关键字去搜。后来我想到,可以把必须使用的id封装到一个类中,把链表拆分成单个的元素,序列化时每次写入新增的元素,而反序列化时,把每个元素还原出来,然后根据元素的属性来组装到各自对应的链表中。

  新增了一个类ToSeriaMV,把需要的ListName信息和MeasuredValue封装起来,每次序列化和反序列的对象都是它。

  第三版代码如下:

 1 class ToSeriaMV {
 2         MeasuredValue _value;
 3         string _listName;
 4        public MeasuredValue Value {
 5             get { return _value; }
 6         }
 7         public String Name
 8         {
 9             get { return _listName; }
10         }
11
12         public ToSeriaMV(MeasuredValue value, string listName){
13             _value = value;
14             _listName = listName;
15         }
16     }
17 class SerializeHelper(){
18         const string _name = "SerializedMV";
19         ToSeriaMV _toSerialMV;
20         List<MeasuredValue> _values;
21
22         public SerializeHelper(MeasuredValue value,String listName)
23         {
24             _toSerialMV = new ToSeriaMV(value, listName);
25         }
26         private SerializeHelper(SerializationInfo info, StreamingContext context)
27         {
28             _deSerializedSuccessful = false;
29
30             _toSerialMV = (ToSeriaMV)info.GetValue(_name, typeof(ToSeriaMV));
31              _deSerializedSuccessful = true;
32         }
33          public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
34         {
35             info.AddValue(_name, _toSerialMV, typeof(ToSeriaMV));
36         }
37 }
38  class Serialize
39     {
40         public bool SerializeMeasuredData(MeasuredValue value, String listName)
41             SerializeHelper data = new SerializeHelper(value, listName );
42             FileSerializer.Serialize(stream, data);
43         }
44         public bool DeSerializeMeasuredData(List<MeasuredValue> values)
45         {
46                 SerializeHelper data = null;
47                 ToSeriaMV toSerialMv = null;
48                 stream = File.Open(_fileName, FileMode.Open, FileAccess.Read);
49
50
51                 while(stream.Position<stream.Length){
52                     data = FileSerializer.Deserialize<SerializeHelper>(stream);
53                     ret = data.GetInfo(out toSerialMv);
54                         if(ret==false)
55                             break;
56                         AddToList(toSerialMv, values);
57                 }
58         }
59     }

  测试一切正常,搞定了。

  发现有些思路什么的不太好写出来,是自己整理的不够清楚,不够到位?

时间: 2024-10-19 06:38:49

C#序列化链表的相关文章

php spl数据结构

1.双链表SplDoublyLinkedList 结构如图: 类定义: SplDoublyLinkedList implements Iterator , ArrayAccess , Countable { /* 方法 */ public __construct ( void ) //构造函数 public void add ( mixed $index , mixed $newval )//在特定位置添加值,原位置的值向后退 public mixed bottom ( void ) //返回链

LinkedList的源码分析

1. LinkedList的定义  1.1  继承于AbstractSequentialList的双向链表,可以被当作堆栈.队列或双端队列进行操作 1.2  有序,非线程安全的双向链表,默认使用尾部插入法 1.3 适用于频繁新增或删除场景,频繁访问场景请选用ArrayList 1.4 插入和删除时间复杂为O(1),其余最差O(n) 1.5 由于实现Deque接口,双端队列相关方法众多 2. LinkedList的继承体系        继承 AbstractSequentialList,能被当作

如何将类序列化并直接存储入数据库

参考代码1 可以使用.net提供的序列化和反序列化方法来实现,你可将对象序列化成XML字符串,然后存入数据库中,当你要使用对象的时候,再把数据库中保存字符串反序列化成对象就可以使用了,以下为示例代码: public class Cat { public string Color { get; set; } public int Speed { get; set; } public string Name{ get; set; } } //序列化 var cat1=new Cat{Color="W

[Think In Java]基础拾遗3 - 容器、I/O、NIO、序列化

目录 第十一章 持有对象第十七章 容器深入研究第十八章 Java I/O系统 第十一章 持有对象 1. java容器概览 java容器的两种主要类型(它们之间的主要区别在于容器中每个“槽”保存的元素个数):Collection和Map. (1)Collection是一个独立元素的序列,这些元素都服从一条或者多条规则.Collection概括了序列的概念——一种存放一组对象的方式. List:按照插入的顺序保存元素(ArrayList,LinkedList) Set:不能有重复元素(HashSet

MFC文件操作、序列化机制

一 MFC的文件操作 1 相关类 CFile类-封装了文件句柄以及操作文件的API函数. CFileFind类-封装了文件搜索功能. 2CFile类的使用 2.1 文件读写 2.1.1 创建或者打开文件 CFile::Create 2.1.2 文件读写 CFile::Read/Write 2.1.3 关闭文件 CFile::Close 注意:1 文件读写需要异常处理 2 注意文件的指针位置 2.2 文件属性的获取和设置 2.2.1 CFile::GetStatus 2.2.2 CFile::Se

MessagePack 新型序列化反序列化方案

进入在学习redis的时候,在文中看到了关于MessagePack的简介,发现非常有意思,于是就花了点时间大致了解了下. MessagePack介绍: MessagePack is an efficient binary serialization format.It lets you exchange data among multiple languages like JSON. But it's faster and smaller.Small integers are encoded i

新型序列化类库MessagePack,比JSON更快、更小的格式

MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON. But it's faster and smaller. Small integers are encoded into a single byte, and typical short strings require only one extra byte i

transient与序列化

transient的作用: 修饰实力域,使其从一个类的默认序列化形式中省略(即默认序列化方式不对该字段做写与读 存取操作) 应用场景: 业务需要,不宜做序列化 如银行密码等 信息不希望在网络和磁盘等地方存储,所以可以用 transient 声明,从而保证相应信息无法从磁盘读取.(此例源于网上观点,个人不太赞同) 默认的序列化方式不适合,采用自定义序列化的方式 例hashMap中对元素的存储.java 7中hashMap元素的存储结构为 表 (table)+ 链(结点构成的链)的存储结构.其中根据

【大话QT之七】QT序列化操作

应用需求: 在网盘开发过程中有这样一个需求.即对文件版本号进行控制,即记录文件版本号的更替信息,这里说的更替信息不过记录不同一时候刻的文件变化,即文件的增.删.改.重命名等操作.在每一个待监控的文件夹下都会保存一份文件.记录文件变化的增量信息.每次低版本号到高版本号升级的时候就能够通过消元合并操作高速地进行.关于文件版本号控制的详细实现方案会在开发完好后列出.这里只指出它的保存方式,即将文件操作的实例对象序列化后保存在文件里. 序列化的实现: 这里我们採用QDataStream来实现序列化,QT