.net序列化与反序列化——提供多次存储对象集后读取不完全解决方案

||问题:

       文本文档读取序列化文件时只能读取第一次序列化对象或对象集,而多次序列化存到同一个文本文件中不能完全读取。最近做一个简单的学生管理系统,涉及到多次将学生对象序列化后追加存储到同一个文档中。在查看所有学生的时候总是读取不完全,折腾了好长时间,想到了以下一个相对权宜之策。

1、对象序列化反序列化简述

      对象序列化是指将对象转化成流的过程。

      反序列化与之相反,是将流转换成对象。这两个过程组合起来,就使得数据能轻松的以对象或对象集为单位进行存储传输。

2、序列化反序列化步骤

      用serializable标识类

      调用BinaryFormattersoapFormatterXmlSerializer将其序列化

      反序列调用Deserialize

3、简单对象序列化与反序列化

       说明问题:第二次追加存储到第一次的文档后面,反序列化时就不能读取所有已经序列化的对象,而只能读取第一次序列化的对象(集)。下面是出现这个问题的程序。

参考程序: 

//引用他人资源说明一下问题局限性。只能序列化一次,再次追加存储后,如果反序列化就不能取出所有对象
//----------二进制方式,可以使用BinaryFormatter 类来以二进制格式将对象或整个连接对象图形序列化和反序列化
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using System.Collections.Generic;

namespace Formatter
{
    [Serializable]
    public class Account
    {
        public int UserID;
        public string Username;
    }
    class BinaryFormatterTest
    {
        public void BinaryFormat()
        {
            Account[] accounts = { 
                                     new Account(){ UserID = 1, Username = "test1" },
                                     new Account(){ UserID = 2, Username = "test2" },
                                     new Account(){ UserID = 3, Username = "test3"  }                               
                                 };

            string savePath = @"e:\BinarySerializerTest.bin";
            BinaryFormatter formatter = new BinaryFormatter();
                                                                                                         
            using (FileStream writeStream = new FileStream(savePath, FileMode.Append, FileAccess.Write))  //这边是Create没问题,但如果追加根本读不完啊
            {
                formatter.Serialize(writeStream, accounts); //这里面只序列化一次,读者可以试着在序列化一次试试,或者在运行一次,追加存储
                //formatter.Serialize(writeStream, accounts); //追加存储,取就会出问题
               
                writeStream.Close();
                using (FileStream readStream = new FileStream(savePath, FileMode.Open, FileAccess.Read))
                {
                    Account[] deSerializedValue = formatter.Deserialize(readStream) as Account[];
                    if (deSerializedValue != null && deSerializedValue.Length > 0)
                    {
                        for (int i = 0; i < deSerializedValue.Length; i++)
                        {
                            Console.WriteLine("{0}\tUserID = {1}, Username = {2}", i, deSerializedValue[i].UserID, deSerializedValue[i].Username);
                        }
                    }
                }
            }
            Console.ReadKey();
        }
    
    }
}

4、解决办法:

       设第二次序列化的集合为List<Student>stuList,在第二次序列化之前,把第一次序列化的对象集反序列化取出,存储到List<>的泛型化集合stuListRead中,然后用foreach语句将stuListRead中的所有元素添加到stuList中,然后一起序列化,覆盖原文件存储。

       这里面会遇到一个问题,就是原文件为空的情况,反序列化取出存储到stuList集合时,就会出现“流为空”异常,读者可以在反序列化之前进行文件信息判断,fi.Length?=0;如果不等于0在进行反序列化即可。读者可以参考以下程序。

 

5、Student类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StudentManagement
{
    /*
       添加一个学生类Student,该类封装学生的一些基本信息(学号、姓名、年龄等字段),
     * 重载一个带参数的构造函数,为学生的基本信息字段初始化。*/
    [Serializable]
    class Student
    {
        private int stuNum;  //学号

        public int StuNum
        {
            get { return stuNum; }
            set { stuNum = value; }
        }

        private string stuName;  //姓名

        public string StuName
        {
            get { return stuName; }
            set { stuName = value; }
        }

        private string stuSex;     //性别

        public string StuSex
        {
            get { return stuSex; }
            set { stuSex = value; }
        }

        private string stuMajor;    //专业

        public string StuMajor
        {
            get { return stuMajor; }
            set { stuMajor = value; }
        }

        private string stuClass;    //班级

        public string StuClass
        {
            get { return stuClass; }
            set { stuClass = value; }
        }
        
        //构造函数初始化
        public Student(int stuNum, string stuName, string stuSex, string stuMajor, string stuClass)
        {
            this.stuNum = stuNum;
            this.stuName = stuName;
            this.stuSex = stuSex;
            this.stuMajor = stuMajor;
            this.stuClass = stuClass;
        }
    }
}

6、FileAccessOperate文件操作类

     导入命名空间

using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

 

定义一个文件目录项:

static string txtDictionary=@"e:\01111104\";

 

反序列化读方法:

//读方法
        public List<Student> StuRead()
        {
            string path=txtDictionary+"stu.dat";    //学生信息存储路径
           
            FileStream stream = new FileStream(path,FileMode.Open,FileAccess.Read);
            BinaryFormatter bf = new BinaryFormatter(); //创建序列化对象
            List<Student> stuList;
                      
            stuList = bf.Deserialize(stream) as List<Student>;
            
            stream.Close();
            return stuList;
        }

 

序列化写方法:

 //写方法
        public void StuWrite(List<Student> stuList)
        {            
            string path = txtDictionary + "stu.dat";    //学生信息存储路径

            FileInfo fi = new FileInfo(path);

            //判断文件是否存在
            if (fi.Exists == false)
            {
                FileStream fs = new FileStream(path,FileMode.Create);
                fs.Close();
                fi = new FileInfo(path);
            }
            //判断文件是否为空,即是否是第一次序列化存储
            if (fi.Length > 0)
            {
                //如果不为空,即已经进行过序列化存储,需将之前存的信息,反序列化读取,添加到要存储的对象集,覆盖存储
                List<Student> StuListRead = StuRead();

                foreach (Student stu in StuListRead)
                {
                    stuList.Add(stu);
                }
            }

            Stream stream = new FileStream(path, FileMode.Create, FileAccess.Write);
            BinaryFormatter bf = new BinaryFormatter(); //创建序列化对象 

            //序列化
            bf.Serialize(stream, stuList);
            stream.Close();
        }

7、总结

        这样就能解决对象集每次只能读取第一次序列化的问题,这样能把所有存储的学生对象全部读出。关键在于每次序列化后都产生独立的对象集存储在文本文档中,够每次序列化只能读取第一个对象集。通过在写之前进行读取,和要写的对象集合并成一个对象集重新覆盖写入,实际上文本文档中只存储了一个对象集,这样就能反序列化读取所有对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值