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

      测试一切正常,搞定了。

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

  • 相关阅读:
    HDU 1009 FatMouse' Trade(简单贪心 物品可分割的背包问题)
    HDU 1006 Tick and Tick(时钟,分钟,秒钟角度问题)
    hdu 2099 整除的尾数
    hdu 2098 分拆素数和(一个偶数拆分成两个不同素数和 拆法数量)
    旅游电车(cogs 1175)
    校长的收藏(洛谷 U4534)
    HXY烧情侣(洛谷 2194)
    矩形面积求并(codevs 3044)
    楼房(洛谷 1382)
    选择数字(codevs 3327)
  • 原文地址:https://www.cnblogs.com/Jack47/p/2766471.html
Copyright © 2020-2023  润新知