binarysd formatterr序列化一对象,升级后该类增加字段,怎么办

解析C# BinaryFormatter实现序列化
解析C# BinaryFormatter实现序列化
  C# BinaryFormatter实现序列化,我们知道在.NET框架里提供了C# BinaryFormatter,那么他是如何实现序列化操作的呢,首先我们来看看C# BinaryFormatter的概念以及作用。
  C# BinaryFormatter的介绍:
  BinaryFormatter使用二进制格式化程序进行序列化。您只需创建一个要使用的流和格式化程序的实例,然后调用格式化程序的 Serialize 方法。流和要序列化的对象实例作为参数提供给此调用。类中的所有成员变量(甚至标记为 private 的变量)都将被序列化。
  C# BinaryFormatter使用实例:
  首先我们创建一个类:    [Serializable] &  &  public&class&MyObject&{ &  &  &public&int&n1&=&0; &  &  &public&int&n2&=&0; &  &  &public&String&str&=&null; &  &  } &
  Serializable属性用来明确表示该类可以被序列化。同样的,我们可以用NonSerializable属性用来明确表示类不能被序列化。接着我们创建一个该类的实例,然后序列化,并存到文件里持久:    MyObject&obj&=&new&MyObject(); &  &  obj.n1&=&1; &  &  obj.n2&=&24; &  &  obj.str&=&"一些字符串"; &    IFormatter&formatter&=&new&BinaryFormatter(); &  &  Stream&stream&=&new&FileStream( &  "MyFile.bin",&FileMode.Create,& &  FileAccess.Write,&FileShare.None); &  &  formatter.Serialize(stream,&obj); &  &  stream.Close(); &
  而将对象还原到它以前的状态也非常容易。首先,创建格式化程序和流以进行读取,然后让格式化程序对对象进行反序列化。    IFormatter&formatter&=&new&BinaryFormatter(); &  &  Stream&stream&=&new&FileStream( &  "MyFile.bin",&FileMode.Open,& &  FileAccess.Read,&FileShare.Read); &  &  MyObject&obj&= &  &(MyObject)&formatter.Deserialize(fromStream); &  &  stream.Close(); &  &  &  Console.WriteLine("n1:&{0}",&obj.n1); &  Console.WriteLine("n2:&{0}",&obj.n2); &  Console.WriteLine("str:&{0}",&obj.str); &
  C# BinaryFormatter实现序列化的详细内容就向你介绍到这里,希望对你了解和学习C# BinaryFormatter类有所帮助。
H3C认证Java认证Oracle认证
基础英语软考英语项目管理英语职场英语
.NETPowerBuilderWeb开发游戏开发Perl
二级模拟试题一级模拟试题一级考试经验四级考试资料
软件测试软件外包系统分析与建模敏捷开发
法律法规历年试题软考英语网络管理员系统架构设计师信息系统监理师
高级通信工程师考试大纲设备环境综合能力
路由技术网络存储无线网络网络设备
CPMP考试prince2认证项目范围管理项目配置管理项目管理案例项目经理项目干系人管理
职称考试题目
招生信息考研政治
网络安全安全设置工具使用手机安全
生物识别传感器物联网传输层物联网前沿技术物联网案例分析
Java核心技术J2ME教程
Linux系统管理Linux编程Linux安全AIX教程
Windows系统管理Windows教程Windows网络管理Windows故障
数据库开发Sybase数据库Informix数据库
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&java(60)
平时我们在Java内存中的对象,是无法进行IO操作或者网络通信的,因为在进行IO操作或者网络通信的时候,人家根本不知道内存中的对象是个什么东西,因此必须将对象以某种方式表示出来,即存储对象中的状态。一个Java对象的表示有各种各样的方式,Java本身也提供给了用户一种表示对象的方式,那就是序列化。换句话说,序列化只是表示对象的一种方式而已。OK,有了序列化,那么必然有反序列化,我们先看一下序列化、反序列化是什么意思。
序列化:将一个对象转换成一串二进制表示的字节数组,通过保存或转移这些字节数据来达到持久化的目的。
反序列化:将字节数组重新构造成对象。
默认序列化
序列化只需要实现java.io.Serializable接口就可以了。序列化的时候有一个serialVersionUID参数,Java序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化,Java虚拟机会把传过来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的实体类,可以进行反序列化,否则Java虚拟机会拒绝对这个实体类进行反序列化并抛出异常。serialVersionUID有两种生成方式:
1、默认的1L
2、根据类名、接口名、成员方法以及属性等来生成一个64位的Hash字段
如果实现java.io.Serializable接口的实体类没有显式定义一个名为serialVersionUID、类型为long的变量时,Java序列化机制会根据编译的.class文件自动生成一个serialVersionUID,如果.class文件没有变化,那么就算编译再多次,serialVersionUID也不会变化。换言之,Java为用户定义了默认的序列化、反序列化方法,其实就是ObjectOutputStream的defaultWriteObject方法和ObjectInputStream的defaultReadObject方法。看一个例子:
1 public class SerializableObject implements Serializable
private static final long serialVersionUID = 1L;
private String str0;
private transient String str1;
private static String str2 = &abc&;
public SerializableObject(String str0, String str1)
this.str0 = str0;
this.str1 = str1;
public String getStr0()
return str0;
public String getStr1()
return str1;
1 public static void main(String[] args) throws Exception
File file = new File(&D:& + File.separator + &s.txt&);
OutputStream os = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(new SerializableObject(&str0&, &str1&));
oos.close();
InputStream is = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(is);
SerializableObject so = (SerializableObject)ois.readObject();
System.out.println(&str0 = & + so.getStr0());
System.out.println(&str1 = & + so.getStr1());
ois.close();
先不运行,用一个二进制查看器查看一下s.txt这个文件,并详细解释一下每一部分的内容。
第1部分是序列化文件头
◇AC ED:STREAM_MAGIC序列化协议
◇00 05:STREAM_VERSION序列化协议版本
◇73:TC_OBJECT声明这是一个新的对象
第2部分是要序列化的类的描述,在这里是SerializableObject类
◇72:TC_CLASSDESC声明这里开始一个新的class
◇00 1F:十进制的31,表示class名字的长度是31个字节
◇63 6F 6D ... 65 63 74:表示的是“com.xrq.test.SerializableObject”这一串字符,可以数一下确实是31个字节
◇00 00 00 00 00 00 00 01:SerialVersion,序列化ID,1
◇02:标记号,声明该对象支持序列化
◇00 01:该类所包含的域的个数为1个
第3部分是对象中各个属性项的描述
◇4C:字符&L&,表示该属性是一个对象类型而不是一个基本类型
◇00 04:十进制的4,表示属性名的长度
◇73 74 72 30:字符串“str0”,属性名
◇74:TC_STRING,代表一个new String,用String来引用对象
第4部分是该对象父类的信息,如果没有父类就没有这部分。有父类和第2部分差不多
◇00 12:十进制的18,表示父类的长度
◇4C 6A 61 ... 6E 67 3B:“L/java/lang/S”表示的是父类属性
◇78:TC_ENDBLOCKDATA,对象块结束的标志
◇70:TC_NULL,说明没有其他超类的标志
第5部分输出对象的属性项的实际值,如果属性项是一个对象,这里还将序列化这个对象,规则和第2部分一样
◇00 04:十进制的4,属性的长度
◇73 74 72 30:字符串“str0”,str0的属性值
从以上对于序列化后的二进制文件的解析,我们可以得出以下几个关键的结论:
1、序列化之后保存的是类的信息
2、被声明为transient的属性不会被序列化,这就是transient关键字的作用
3、被声明为static的属性不会被序列化,这个问题可以这么理解,序列化保存的是对象的状态,但是static修饰的变量是属于类的而不是属于变量的,因此序列化的时候不会序列化它
接下来运行一下上面的代码看一下
str0 = str0
str1 = null
因为str1是一个transient类型的变量,没有被序列化,因此反序列化出来也是没有任何内容的,显示的null,符合我们的结论。
手动指定序列化过程
Java并不强求用户非要使用默认的序列化方式,用户也可以按照自己的喜好自己指定自己想要的序列化方式----只要你自己能保证序列化前后能得到想要的数据就好了。手动指定序列化方式的规则是:
进行序列化、反序列化时,虚拟机会首先试图调用对象里的writeObject和readObject方法,进行用户自定义的序列化和反序列化。如果没有这样的方法,那么默认调用的是ObjectOutputStream的defaultWriteObject以及ObjectInputStream的defaultReadObject方法。换言之,利用自定义的writeObject方法和readObject方法,用户可以自己控制序列化和反序列化的过程。
这是非常有用的。比如:
1、有些场景下,某些字段我们并不想要使用Java提供给我们的序列化方式,而是想要以自定义的方式去序列化它,比如ArrayList的elementData、HashMap的table(至于为什么在之后写这两个类的时候会解释原因),就可以通过将这些字段声明为transient,然后在writeObject和readObject中去使用自己想要的方式去序列化它们
2、因为序列化并不安全,因此有些场景下我们需要对一些敏感字段进行加密再序列化,然后再反序列化的时候按照同样的方式进行解密,就在一定程度上保证了安全性了。要这么做,就必须自己写writeObject和readObject,writeObject方法在序列化前对字段加密,readObject方法在序列化之后对字段解密
上面的例子SerializObject这个类修改一下,主函数不需要修改:
1 public class SerializableObject implements Serializable
private static final long serialVersionUID = 1L;
private String str0;
private transient String str1;
private static String str2 = &abc&;
public SerializableObject(String str0, String str1)
this.str0 = str0;
this.str1 = str1;
public String getStr0()
return str0;
public String getStr1()
return str1;
private void writeObject(java.io.ObjectOutputStream s) throws Exception
System.out.println(&我想自己控制序列化的过程&);
s.defaultWriteObject();
s.writeInt(str1.length());
for (int i = 0; i & str1.length(); i++)
s.writeChar(str1.charAt(i));
private void readObject(java.io.ObjectInputStream s) throws Exception
System.out.println(&我想自己控制反序列化的过程&);
s.defaultReadObject();
int length = s.readInt();
char[] cs = new char[length];
for (int i = 0; i & i++)
cs[i] = s.readChar();
str1 = new String(cs, 0, length);
直接看一下运行结果
我想自己控制序列化的过程
我想自己控制反序列化的过程
str0 = str0
str1 = str1
看到,程序走到了我们自己写的writeObject和readObject中,而且被transient修饰的str1也成功序列化、反序列化出来了----因为手动将str1写入了文件和从文件中读了出来。不妨再看一下s.txt文件的二进制:
看到橘黄色的部分就是writeObject方法追加的str1的内容。至此,总结一下writeObject和readObject的通常用法:
先通过defaultWriteObject和defaultReadObject方法序列化、反序列化对象,然后在文件结尾追加需要额外序列化的内容/从文件的结尾读取额外需要读取的内容。
复杂序列化情况总结
虽然Java的序列化能够保证对象状态的持久保存,但是遇到一些对象结构复杂的情况还是比较难处理的,最后对一些复杂的对象情况作一个总结:
1、当父类继承Serializable接口时,所有子类都可以被序列化
2、子类实现了Serializable接口,父类没有,父类中的属性不能序列化(不报错,数据丢失),但是在子类中属性仍能正确序列化
3、如果序列化的属性是对象,则这个对象也必须实现Serializable接口,否则会报错
4、反序列化时,如果对象的属性有修改或删减,则修改的部分属性会丢失,但不会报错
5、反序列化时,如果serialVersionUID被修改,则反序列化时会失败
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:19157次
排名:千里之外
转载:271篇
(1)(3)(3)(12)(7)(68)(168)(21)序列化、压缩、解压缩、反序列化对象_51自学网
序列化、压缩、解压缩、反序列化对象
using S using System.Collections.G using System.T using System.IO; using System.Xml.S usin
using System.Collections.G
using System.T
using System.IO;
using System.Xml.S
using System.X
using System.D
using System.Runtime.Serialization.Formatters.B
using System.Runtime.S
namespace JTK.IOHelper
& & public class SerializerDeserialize
& & & & public static byte [] Serializer(object obj)
& & & & & & IFormatter formatter = new BinaryFormatter();//定义BinaryFormatter以序列化object对象 &
& & & & & & MemoryStream ms = new MemoryStream();//创建内存流对象 &
& & & & & & formatter.Serialize(ms, obj);//把object对象序列化到内存流 &
& & & & & & byte[] buffer = ms.ToArray();//把内存流对象写入字节数组 &
& & & & & & ms.Close();//关闭内存流对象 &
& & & & & & ms.Dispose();//释放资源 &
& & & & & & MemoryStream msNew = new MemoryStream();
& & & & & & GZipStream gzipStream = new GZipStream(msNew, press, true);//创建压缩对象 &
& & & & & & gzipStream.Write(buffer, 0, buffer.Length);//把压缩后的数据写入文件 &
& & & & & & gzipStream.Close();//关闭压缩流,这里要注意:一定要关闭,要不然解压缩的时候会出现小于4K的文件读取不到数据,大于4K的文件读取不完整 & & & & & & &
& & & & & & gzipStream.Dispose();//释放对象 &
& & & & & & msNew.Close();
& & & & & & msNew.Dispose();
& & & & & & return msNew.ToArray();
& & & & /// &summary& &
& & & & /// 反序列化压缩的object &
& & & & /// &/summary& &
& & & & /// &param name=&_filePath&&&/param& &
& & & & /// &returns&&/returns& &
& & & & public static object Deserialize(byte[] bytes)
& & & & & & MemoryStream msNew = new MemoryStream(bytes);
& & & & & & msNew.Position = 0;
& & & & & & GZipStream gzipStream = new GZipStream(msNew, CompressionMode.Decompress);//创建解压对象 &
& & & & & & byte[] buffer = new byte[4096];//定义数据缓冲 &
& & & & & & int offset = 0;//定义读取位置 &
& & & & & & MemoryStream ms = new MemoryStream();//定义内存流 &
& & & & & & while ((offset = gzipStream.Read(buffer, 0, buffer.Length)) != 0)
& & & & & & {
& & & & & & & & ms.Write(buffer, 0, offset);//解压后的数据写入内存流 &
& & & & & & }
& & & & & & BinaryFormatter sfFormatter = new BinaryFormatter();//定义BinaryFormatter以反序列化object对象 &
& & & & & & ms.Position = 0;//设置内存流的位置 &
& & & & & &
& & & & & & try
& & & & & & {
& & & & & & & & obj = (object)sfFormatter.Deserialize(ms);//反序列化 &
& & & & & & }
& & & & & & catch
& & & & & & {
& & & & & & & &
& & & & & & }
& & & & & & finally
& & & & & & {
& & & & & & & & ms.Close();//关闭内存流 &
& & & & & & & & ms.Dispose();//释放资源 &
& & & & & & }
& & & & & & gzipStream.Close();//关闭解压缩流 &
& & & & & & gzipStream.Dispose();//释放资源 &
& & & & & & msNew.Close();
& & & & & & msNew.Dispose();
& & & & & &
& & & & } &
本站推荐文章:
C# 指针之美
将C#图像库的基础部分开源了( /xiaotie/GebImage )。这个库比较...
C#编写FTP密码爆破器
在这之前,我必须要声明的是,代码仅供学习参考使用,以此代码发生的后果,请自己负责...
C#开发的高性能EXCEL导入、导出工具DataPie(
先看看工具界面: 登录界面: 主界面: 主要代码: 1. 把 excel 文件读到 DataTable /...
C#嵌入x86汇编――一个GPIO接口的实现
开始进入工业自动化,买的工控机带有GPIO接口,可用于直接控制继电器。 从厂家拿到接...
c#读写共享内存操作封装函数
c#共享内存操作相对c++共享内存操作来说原理是一样,但是c#会显得有点复杂。 现把昨天...
C# .NET 基本概念 基础教程
1. private、 protected、 public、 internal 修饰符的访问权限。 private : 私有成员...
C#综合细说进程、应用程序域与上下文
引言 本文主要是介绍进程(Process)、应用程序域(AppDomain)、.NET上下文(Context...
也说C#利用Web Service实现短信发送
通过编程方式实现短信息的发送对很多人来说是一件比较烦杂的事情,目前一般的解决方法...
C#图片水印和缩略图片
网上代码很多的,以前老是到处抄,所以为了自己以后不在抄,就自己学习了一下,还很肤浅 ...
C#匿名方法的用法
匿名方法,是C#2.0的一个特点。最近看了一篇说的还挺详细的文章,修改了一下转了过来...
本站热点文章:
C#操作Word完全方法
前提:引入COM组件 1、创建 object oMissing = System.Reflection.Missing.V Wor...
C# webservice调用方法总结
一、WebService在cs后台程序中的调用 A、通过命名空间和类名直接调用 示例: WebServi...
一个c#即时监控小程序
关键词: 委托 线程 异步操作 大数据存储过程分页 实时刷新界面数据 声音报警 任务栏...
c#读取Excel数据到Gridview
#region 读取Excel数据到Gridview public void ReadExcel(string sExcelFile, GridVie...
键盘钩子在C#中的设计
趁空闲的时间,对键盘钩子进行了学习,通过C#这门语言来设计和实现:下面是我设计的类...
C#程序实现动态调用DLL的研究
摘 要: 在《 csdn 开发高手》 2004 年第 03 期中的《化功**将 DLL 嵌入 EXE 》一文...
C#的4个基本技巧
1. 如果可能尽量使用接口来编程 .NET框架包括类和接口,在编写程序的时候,你可能知道...
如何使用C#实现QQ号码的申请
腾讯向大众提供了申请QQ的界面,方便很多潜在用户加入QQ大军中,注册页面是
23个C#经典实用技巧
这些技巧不好找,我归类总结了一下,对大家访问使用也方便,好了,列表如下: 1.怎样...
使用C#打印大图片
C# 打印大图片有两种方式 1、缩小到纸张大小 2、自动分割,分页打印 主界面 缩小到纸...
------分隔线----------------------------
上一篇:C# 设置Excel常用属性
下一篇:C#图片水印和缩略图片
进入详细评论页&&
Powered by DedeCMSV55_GBK &
DesDev Inc.
Copyright &
.NET教程网 网站合作及版权问题联系QQ 蜀ICP备号
(责任编辑:admin)
------分隔线----------------------------
初学者在学习程序的过程中很重要的一个学习方法就是读源代码,但如果对语言本身的了解...

我要回帖

更多关于 c binaryformatter 的文章

 

随机推荐