||问题:

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

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

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

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

2、序列化反序列化步骤

用serializable标识类

调用BinaryFormatter、soapFormatter或XmlSerializer将其序列化

反序列调用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. 人工智能交互集成在线语音合成能力的Tips
  2. Oracle定时计划快速使用
  3. .NET面试题解析(11)-SQL语言基础及数据库基本原理
  4. Sun Grid Engine (SGE)大型集群作业调度系统
  5. golang的连接池例子
  6. js 事件函数中的参数带换行符或换行标签都不能起作用的解决方法
  7. FreeMarker中List排序
  8. oracle查看最大长度
  9. hdu1331 按着题目的公式直接写
  10. C# Winform里面用Console.WriteLine输出到哪了
  11. c程序设计语言_习题1-19_编写函数reverse(s)将字符串s中字符顺序颠倒过来。
  12. ASP.NET MVC——Controller的激活
  13. TypeScript 基本语法
  14. [多线程] Web 项目中,少有涉及到的一次多线程编程的经验
  15. 出行服务类API调用的代码示例合集:长途汽车查询、车型大全、火车票查询等
  16. 用Laravel Sms实现 laravel短信验证码的发送
  17. Java基础——0 前言
  18. hdu1242 DFS基础(回溯的重要性)
  19. openstry lua redis实现负载均衡
  20. PowerDesigner V16.5 安装教程以及汉化(数据库建模)

热门文章

  1. DialogFragment创建默认dialog
  2. JS常用正则表达式大全
  3. 公网通过代理访问阿里云vpc redis
  4. java统计中英文字数 Java问题通用解决代码
  5. 获取bundle文件下的资源
  6. sql CHARINDEX() 与 PATINDEX() LEN() substring() COLLATE RAISERROR
  7. java 中的 i++ 和 ++i
  8. go http请求基础
  9. IntelliJ IDEA(2017)下载并破解
  10. Python学习笔记(一)三步走安装pip