.NET基础 (10)流和序列化
流和序列化
1 什么是流,.NET中有哪些常见的流
2 如何使用压缩流
3 Serializable特性有何作用
4 .NET提供了哪几种可进行序列化操作的类型
5 如何自定义序列化和反序列化的过程
流和序列化
1 什么是流,.NET中有哪些常见的流
流是对字节集合对象的一种操作。.NET中常见的流类型有FileStream、NetworkStream、UnmanagedMemoryStream、MemoryStream等。
流的示例:
partial class UseStream
{
//从一个流总读取所有字节
static Byte[] ReadAllBytes(Stream stream, int bufferlength)
{
Byte[] buffer = new Byte[bufferlength];
List<Byte> result = new List<Byte>();
int read;
while ((read = stream.Read(buffer, , bufferlength)) > )
{
if (read < bufferlength)
{
Byte[] temp = new Byte[read];
Array.Copy(buffer, temp, read);
result.AddRange(temp);
}
else
result.AddRange(buffer);
}
return result.ToArray();
}
//把字节写入一个流中
static void WriteAllBytes(Stream stream, Byte[] data, int bufferlength)
{
Byte[] buffer = new Byte[bufferlength];
for (long i = ; i < data.LongLength; i += bufferlength)
{
int length = bufferlength;
if (i + bufferlength > data.LongLength)
length = (int)(data.LongLength - i);
Array.Copy(data, i, buffer, , length);
stream.Write(buffer, , length);
}
}
}
partial class UseStream
{
private const int bufferlength = ; static void Main(string[] args)
{
//创建一个文件,并写入内容
String filename = "C:\\TestStream.txt";
String filecontent = GetTestString();
try
{
//创建文件并写入内容
using (FileStream fs =
new FileStream(filename, FileMode.Create))
{
Byte[] bytes = Encoding.Default.GetBytes(filecontent);
WriteAllBytes(fs, bytes, bufferlength);
fs.Close();
} //读取文件并且打印出来
using (FileStream fr =
new FileStream(filename, FileMode.Open))
{
Byte[] result = ReadAllBytes(fr, bufferlength);
Console.WriteLine(Encoding.Default.GetString(result));
fr.Close();
}
}
finally
{
//清除测试文件
try
{
if (File.Exists(filename))
File.Delete(filename);
}
finally { }
Console.Read();
}
}
//取得测试数据
static String GetTestString()
{
StringBuilder builder = new StringBuilder();
for (int i = ; i < ; i++)
builder.Append("我是测试数据\r\n");
return builder.ToString();
} }
所有常见的流类型都继承自System.IO.Stream。Stream类型实现了IDisposable接口,所有的流类型都应该使用using语句确保Dispose方法被调用。
2 如何使用压缩流
System.IO.Compression下定义了两个用于压缩数据的类型:DeflateStream和GZioStream,两者都继承自System.IO.Stream。在.NET4之前,这两类的压缩算法并不出色,并且不支持调整压缩率。有些第三方组件如SharpZipLib实现了更高效的压缩解压算法。在.NET4中,对它们做了改善,提供了更好的压缩算法。
示例:
private const int bufferlength = ; static void Main(string[] args)
{
String test = GetTestString();
Byte[] original = Encoding.Default.GetBytes(test);
Console.WriteLine("数据的原始长度是:" +
original.LongLength.ToString());
//进行压缩
Byte[] compressed = Compress(original);
Console.WriteLine("压缩后的数据长度是:" +
compressed.LongLength);
//进行解压
Byte[] back = DeCompress(compressed);
Console.WriteLine("解压后得到数据长度:" +
back.LongLength.ToString());
Console.WriteLine("解压前后是否相等:"+
test.Equals(Encoding.Default.GetString(back)));
Console.Read();
} //压缩数据
static Byte[] Compress(Byte[] data)
{
//压缩入这个内存流
using (MemoryStream target = new MemoryStream())
{
using (GZipStream gs =
new GZipStream
(target,CompressionMode.Compress,true))
{
WriteAllBytes(gs, data, bufferlength);
}
return target.ToArray();
}
}
//解压数据
static Byte[] DeCompress(Byte[] data)
{
using (MemoryStream source = new MemoryStream(data))
{
using (GZipStream gs =
new GZipStream
(source, CompressionMode.Decompress, true))
{
return ReadAllBytes(gs, bufferlength);
}
}
}
//准备测试数据
static String GetTestString()
{
StringBuilder builder = new StringBuilder();
for (int i = ; i < ; i++)
builder.Append("我是测试数据");
return builder.ToString();
}
//从一个流总读取所有字节
static Byte[] ReadAllBytes(Stream stream, int bufferlength)
{
Byte[] buffer = new Byte[bufferlength];
List<Byte> result = new List<Byte>();
int read;
while ((read = stream.Read(buffer, , bufferlength)) > )
{
if (read < bufferlength)
{
Byte[] temp = new Byte[read];
Array.Copy(buffer, temp, read);
result.AddRange(temp);
}
else
result.AddRange(buffer);
}
return result.ToArray();
}
//把字节写入一个流中
static void WriteAllBytes(Stream stream, Byte[] data, int bufferlength)
{
Byte[] buffer = new Byte[bufferlength];
for (long i = ; i < data.LongLength; i += bufferlength)
{
int length = bufferlength;
if (i + bufferlength > data.LongLength)
length = (int)(data.LongLength - i);
Array.Copy(data, i, buffer, , length);
stream.Write(buffer, , length);
}
}
输出:
数据的原始长度是:12000
压缩后的数据长度是:77 //77是.NET4之后的结果。.NET3.5的结果是 274
解压后得到数据长度:12000
解压前后是否相等:True
3 Serializable特性有何作用
对象实例的序列化,是指把实例对象转换为可方便存储、传输和交互的流。而对象的实例则包含类型的成员变量、类型的名称以及对象所在的程序集等信息。
通过为类型添加Serializable特性,可以使对象申明为可被序列化,即可被诸如BinaryFormatter等实现了IFormatter接口的类型的对象序列化和返序列化。
当一个基类使用了Serializable特性之后,并不意味着其所有子类都能被序列化,必须为每个子类都添加Serializable特性来保证其被正确地序列化。
示例:
class UserSerializable
{
static void Main(string[] args)
{
MyObject obj = new MyObject(, "我是字符串");
Console.WriteLine("初始状态:");
Console.WriteLine(obj); Byte[] data = Serialize(obj);
MyObject newobj = DeSerialize(data);
Console.WriteLine("经过序列化和反序列化后:");
Console.WriteLine(newobj);
Console.Read();
} //序列化对象
static Byte[] Serialize(MyObject obj)
{
IFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
formatter.Serialize(ms, obj);
return ms.ToArray();
}
}
//反序列化对象
static MyObject DeSerialize(Byte[] data)
{
IFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
return (MyObject)formatter.Deserialize(ms);
}
}
}
//一个可序列化的类型
[Serializable]
public class MyObject
{
private int _myInt;
[NonSerialized]
//这个成员不可被序列化
private String _myPrivate;
public MyObject(int i, String s)
{
_myInt = i;
_myPrivate = s;
}
public override string ToString()
{
return "整数是:" + _myInt.ToString() +
"\r\n字符串是:" + _myPrivate;
}
}
输出:
初始状态:
整数是:10
字符串是:我是字符串
经过序列化和反序列化后:
整数是:10
字符串是:
4 .NET提供了哪几种可进行序列化操作的类型
.NET内建了3个可执行序列化的和反序列化的类型:BinaryFormatter、SoapFormatter、XmlSerializer。
BinaryFormatter和SoapFormatter可以对那些有Serializable特性的类型进行序列化和反序列化操作,除了有NonSerialized特性修饰的成员,两者将序列化所有其他成员。而XmlSerializer不需要对象申明了XmlSerializable特性,但它要求对象类型有一个显示的无参公共构造方法,并且它不能序列化对象的非公共成员和由XmlIgnore修饰的成员。
示例:
partial class DoSerialize
{
static void Main(string[] args)
{
MyObject obj = new MyObject(, "我是字符串");
Console.WriteLine("原始对象是:");
Console.WriteLine(obj.ToString()); //使用 SoapFormatter进行序列化
Byte[] data = SoapFormatterSerialize(obj);
Console.WriteLine("SoapFormatter序列化后:");
Console.WriteLine(Encoding.UTF8.GetString(data)); //使用XmlSerializer进行序列化
Byte[] data1 = XmlSerializerSerialize(obj);
Console.WriteLine("XmlSerializer序列化后:");
Console.WriteLine(Encoding.UTF8.GetString(data1));
Console.Read();
}
}
partial class DoSerialize
{
/// <summary>
/// Soap序列化
/// </summary>
static Byte[] SoapFormatterSerialize(MyObject obj)
{
using (MemoryStream ms = new MemoryStream())
{
SoapFormatter sf = new SoapFormatter();
sf.Serialize(ms, obj);
return ms.ToArray();
}
}
/// <summary>
/// Soap反序列化
/// </summary>
static MyObject SoapFormatterDeserialize(Byte[] data)
{
using (MemoryStream ms = new MemoryStream(data))
{
SoapFormatter sf = new SoapFormatter();
return (MyObject)sf.Deserialize(ms);
}
}
/// <summary>
/// 使用XmlSerilizer序列化
/// </summary>
static Byte[] XmlSerializerSerialize(MyObject obj)
{
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer xs = new XmlSerializer(typeof(MyObject));
xs.Serialize(ms, obj);
return ms.ToArray();
}
}
/// <summary>
/// 使用XmlSerilizer反序列化
/// </summary>
static MyObject XmlSerializerDeserialize(Byte[] data)
{
using (MemoryStream ms = new MemoryStream(data))
{
XmlSerializer xs = new XmlSerializer(typeof(MyObject));
return (MyObject)xs.Deserialize(ms);
}
}
}
[Serializable]
public class MyObject
{
//私有成员,不能被XmlSerializer序列化
private int _myInt;
//申明不可被序列化
[NonSerialized]
public String _MyString1;
//申明不可被XmlSerializer序列化
[XmlIgnore]
public String _MyString2;
public MyObject()
{
_myInt = ;
_MyString1 = "";
_MyString2 = "";
}
public MyObject(int i, String s)
{
_myInt = i;
_MyString1 = s;
_MyString2 = s;
}
public override string ToString()
{
return "整数是:" + _myInt.ToString() +
"\r\n字符串1是:" + _MyString1 +
"\r\n字符串2是:" + _MyString2 + "\r\n";
}
}
输出:
原始对象是:
整数是:10
字符串1是:我是字符串
字符串2是:我是字符串
SoapFormatter序列化后:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:MyObject id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/MyTest/MyTest%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<_myInt>10</_myInt>
<_MyString2 id="ref-3">我是字符串</_MyString2>
</a1:MyObject>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XmlSerializer序列化后:
<?xml version="1.0"?>
<MyObject xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<_MyString1>我是字符串</_MyString1>
</MyObject>
5 如何自定义序列化和反序列化的过程
通过实现ISerializable接口中的GetObjectData方法可以实现自定义的序列化,通过添加带有SerializationInfo和StreamingContext参数的构造方法可以自定义反序列化的过程。
示例:
class CustomizeSerialization
{
static void Main(string[] args)
{
MyObjectSon obj = new MyObjectSon(, "我是字符串");
Console.WriteLine("初始对象:");
Console.WriteLine(obj);
Byte[] data = Serialize(obj);
Console.WriteLine("经过序列化和反序列化后:");
Console.WriteLine(DeSerialize(data));
Console.Read();
}
//序列化对象
static Byte[] Serialize(MyObjectSon obj)
{
IFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
formatter.Serialize(ms, obj);
return ms.ToArray();
}
}
//反序列化对象
static MyObjectSon DeSerialize(Byte[] data)
{
IFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
return (MyObjectSon)formatter.Deserialize(ms);
}
} } [Serializable]
class MyObject : ISerializable
{
private int _MyInt;
[NonSerialized]
private String _MyString; public MyObject(int i, String s)
{
_MyInt = i;
_MyString = s;
}
public override string ToString()
{
return "整数是:" + _MyInt.ToString() +
"\r\n字符串是:" + _MyString + "\r\n";
}
//实现反序列化
protected MyObject(SerializationInfo info,
StreamingContext context)
{
_MyInt = info.GetInt32("MyObjectInt");
_MyString = info.GetString("MyObjectString");
}
//实现序列化
public virtual void GetObjectData
(SerializationInfo info, StreamingContext context)
{
info.AddValue("MyObjectInt", _MyInt);
info.AddValue("MyObjectString", _MyString);
}
}
[Serializable]
class MyObjectSon : MyObject
{
private String _SonString; public MyObjectSon(int i, String s)
: base(i, s)
{
_SonString = s;
}
public override string ToString()
{
return base.ToString() + "子类字符串是:" +
_SonString + "\r\n";
}
//实现反序列化
protected MyObjectSon(SerializationInfo info,
StreamingContext context)
: base(info, context)
{
_SonString = info.GetString("MyObjectSonString");
}
//实现序列化
public override void GetObjectData(SerializationInfo info,
StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("MyObjectSonString", _SonString);
}
}
输出:
初始对象:
整数是:10
字符串是:我是字符串
子类字符串是:我是字符串
经过序列化和反序列化后:
整数是:10
字符串是:我是字符串
子类字符串是:我是字符串
转载请注明出处:
作者:JesseLZJ
出处:http://jesselzj.cnblogs.com
.NET基础 (10)流和序列化的更多相关文章
- Java 基础 IO流之序列化
一,前言 在前面的IO中,我们都是讲数据以字符串的形式保存.能不能将一个数组保存到文件呢,当取出数据时也是一个数组,如果能够实现那就完美了.我们都知道比较通用的有JSON格式的序列化,那java中也有 ...
- 01 语言基础+高级:1-8 File类与IO流_day10【缓冲流、转换流、序列化流】
day10[缓冲流.转换流.序列化流] 主要内容 缓冲流 转换流 序列化流 打印流 教学目标 能够使用字节缓冲流读取数据到程序 能够使用字节缓冲流写出数据到文件 能够明确字符缓冲流的作用和基本用法 能 ...
- Java基础-IO流对象之序列化(ObjectOutputStream)与反序列化(ObjectInputStream)
Java基础-IO流对象之序列化(ObjectOutputStream)与反序列化(ObjectInputStream) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.对象的序 ...
- Java基础18:Java序列化与反序列化
更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...
- Java基础IO流(二)字节流小案例
JAVA基础IO流(一)https://www.cnblogs.com/deepSleeping/p/9693601.html ①读取指定文件内容,按照16进制输出到控制台 其中,Integer.to ...
- Java基础-IO流对象之字节流(Stream)
Java基础-IO流对象之字节流(Stream) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在前面我分享的笔记中,我们一直都是在操作文件或者文件夹,并没有给文件中写任何数据.现 ...
- Java基础-IO流对象之File类
Java基础-IO流对象之File类 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.IO技术概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下 ...
- javaSE学习笔记(15) ---缓冲流、转换流、序列化流
javaSE学习笔记(15) ---缓冲流.转换流.序列化流 缓冲流 昨天复习了基本的一些流,作为IO流的入门,今天我们要见识一些更强大的流.比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化 ...
- Java基础00-IO流27
1. File 1.1 File类概述和构造方法 File的构造方法:这三个构造方法可以做同样的事情 代码示例: public class File1 { public static void mai ...
随机推荐
- 【monkeyrunner】monkeyrunner 常见问题
1.monkeyrunner和部分机型的指针位置会出现冲突 问题描述:当我们用monkeyrunner定位坐标时,会打开设置的指针位置服务.当指针位置开启时,运行monkeyrunner时,真机会出现 ...
- 查看ms SQL Server存储过程,函数的内容
方法1:最简单的,右键单击要查看的存储过程,选择“修改”: 方法2: SELECT definition FROM solar.sys.sql_modules WHERE [object_id]=(O ...
- 学习笔记之Tips for Macbook
写给Mac新手的入门指南 - 威锋网 https://mp.weixin.qq.com/s/pqmqGZhNwevx57KeLnzZmg https://bbs.feng.com/read-htm-t ...
- php ini_set更改php.ini配置,通过它修改php.in达到php上传文件大小限制是不行的,除非修改.htaccess文件
PHP ini_set() 无效的原因:如题:我租的是虚拟主机,php.ini里的upload_max_filesize是默认的2M,要直接修改php.ini文件是不可能的.我如果想上传超过2M的怎么 ...
- 记一次在 Ubutun16.04 LTS 系统的 python-environment 安装 MySQL-python 的心(苦)路(笑)旅程
背景 之前项目需要准备线啦, 那么好了~~ 数据库也从测试时使用的 SQLITE 升级到了 MYSQL (高大上的免费且开源的关系型数据库,要不要了解一下!) 巧合的是,同事使用的是MySQL-pyt ...
- Web Api HelpPage
为了方面APP开发人员,服务端的接口都应当提供详尽的API说明.但每次有修改,既要维护代码,又要维护文档,一旦开发进度紧张,很容易导致代码与文档不一致. Web API有一个Help Page插件,可 ...
- 关于phpmailer邮件发送
今天有个需求,要把phpmailer集成到框架里面 所以我去官方下载了 phpmail5.2.6 地址在 https://github.com/PHPMailer/PHPMailer/releases ...
- libtrace 安装 使用 修改
下载 https://github.com/LibtraceTeam/libtrace/releases 解压 进入目录 依赖 sudo apt install libpcap0.8-dev -y a ...
- Cmder的安装
Cmder把conemu,git-for-windows和clink打包在一起,让你无需配置就能使用一个真正干净的Linux终端!性感的外观,强大的功能!代替了Windows原生的Cmd 1. 安裝 ...
- HTTP --meta详解
meta是html语言head区的一个辅助性标签.也许你认为这些代码可有可无.其实如果你能够用好meta标签,会给你带来意想不到的效果,meta标签的作用有:搜索引擎优化(SEO),定义页面使用语言, ...