1.BinaryReader类和BinaryWriter类
BinaryReader
和BinaryWriter
可以用来进行二进制输入/输出,也就是用来读写基本的数据类型(如int
,double
等),而不是原始的字节类型。BinaryReader
和BinaryWriter
不是Stream
类的子类,但它是对Stream
流进行包装,在构造BinaryReader
和BinaryWriter
对象时,需要一个Stream
对象作为其参数。如:
new BinaryReader(myStream);
实际上,这两种类主要是在基本类型和原始字节之间进行转换,因此它们需要处理能够对字节进行I/O的一些基本的Stream
对象,如FileStream或者MemoryStream
。这两种类都有一个BaseStream
属性,通过该属性可以得到对基本的Stream
对象的引用。以下是BinaryWriter
类的一些方法:
BinaryReader
与BinaryWriter
有很相似的功能,有多个不同名字的ReadXXX()
方法。例如,在BinaryWriter
中可以有Write(Int16)
方法和Write(Char)
方法,而在BinaryReader
中则只能有ReadInt16()
方法和ReadChar()
方法。因为,当执行写操作时,writer对象能够根据Write()的参数推断出写入的内容;而当执行读操作时,面对每一个字节流,reader对象并不知道应该如何把这些字节组织到一起。必须通过调用某个特定的函数,才能够告诉reader对象如何把字节流组织到一起。
2.用Stream流进行二进制输入/输出
BinaryReader
及BinaryWriter
可以对Stream
进行包装,从而进行二进制的原始数据的输入/输出。
例,以二进制格式向文件中写入数据,然后再从该文件中读出数据:
using System;
using System.IO;
class Test
{
static void Main(){
try {
FileStream ds = new FileStream("test_binary.dat", FileMode.Create, FileAccess.ReadWrite);
BinaryWriter bw = new BinaryWriter(ds);
// Write some data to the stream;
bw.Write("A string");
bw.Write(142);
bw.Write(97.4);
bw.Write(true);
// Open it for reading;
BinaryReader br = new BinaryReader(ds);
// Move back to the start;
br.BaseStream.Seek(0, SeekOrigin.Begin);
// Read the data
Console.WriteLine(br.ReadString());
Console.WriteLine(br.ReadInt32());
Console.WriteLine(br.ReadDouble());
Console.WriteLine(br.ReadBoolean());
} catch (Exception e) {
Console.WriteLine("Exception:" + e.ToString());
}
}
}
例中创建了一个FileStream
对象,用来对文件进行操作。创建对象时的第二个参数确定文件以什么样的方式打开,在本例中,为FileMode.Create
,表示要创建一个新的文件,或者覆盖已经存在的同名文件。第三个参数决定文件的访问权限,本例中用FileAccess.ReadWrite
,要对文件进行读写操作。
FileStream
可以对自己的进行操作,操作起来通常很不方便,因此FileStream
经常被包装到其他能够对字节进行转换的类中使用。如上,使用了一个BinaryWriter
类,该类能够接收.NET
中的原始类型,并将其转换为字节。然后再把字节传送到FileStream
类中。
程序中然后创建一个BinaryReader
对象用来从FileStream
中读取数据。在使用BinaryReader
之前,必须首先退回到文件的开头,即调用Seek()
对方法FileStream
重新定位,然后从文件中读取数据。
3.使用File的二进制功能
.NET Framework
提供了专门的File类来处理文件的相关功能,File
是个工具类,是个static
类,直接使用“File.方法
”即可。
这些方法中,一类是得到一个流以方便操作,如File.Create(path)
创建或打开一个FileStream
,而File.OpenRead(path)
则得到一个FileStream
用于读,File.OpenWrite(path)
则得到一个FileStream
用于写。
另一类则更方便,打开、读写、关闭文件只有一个方法就行了,包括:
- ①
File. ReadAlIBytes(path)
读到一个文件的所有字节,返回一个字节数组; - ②
File. WriteAllBytes(path,bytes)
写入字节数组到一个文件中; - ③
File. Copy(path,path2)
复制文件。
序列化与反序列化
1.什么是对象序列化
C#对象一般位于内存中,但在现实应用中常常要求在C#程序停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。C#对象序列化(serialize)、反序列化(deserialize)就能够实现该功能。
使用对象序列化,将对象保存到磁盘或输出到网络时,会把其状态保存为一组字节,在未来再将这些字节组转成对象(反序列化)。除了在持久化对象时会用到对象序列化之外,当使用远程方法调用(如Remoting
、WebService
等),或在网络中传递对象时,都会用到对象序列化。另外,也可以将一个对象序列化再反序列化可以得到一个对象的拷贝。
2.简单的序列化及反序列化
System.Runtime.Serialization
命名空间提供了对象序列化和含序列化功能。只要一个类标记了[Serializable]
这个特性(Attribute
),那么它就可以被序列化。要进行序列化及反序列化操作,需要一个实现了IFormatter
的对象,IFormatter
具有Serialize(stream, object)
及Deserialize(stream)
方法。.NET Framework
中已经实现了下面几种IFormatter对象。
- ①
BinaryFormatter
,二进制的格式,可将对象序列化成二进制信息,主要用于对象状态的保存(如游戏状态)、远程调用(Remoting),它的特点是效率较高,但只能在.NET Framework
平台内反序列化。这要用到System.Runtime.Serialization.Formatters.Binary
命名空间。 - ②
XMLDeserialize
,XML的格式化,可将对象序列化成规范的XML信息,主要用于对象状态的保存和数据交换,它的特点是可以与其他平台的语言交换数据。要注意的是,这里不是用IFormatter
,而是用System.XML.Serialization
命名空间中的XmlSerializer
类,它也具有Serialize()
及Deserialize()
方法。 - ③ SoapFormatter,SOAP是XML Web Service远程服务调用的一种格式,主要用于XML Web Service,在Visual Studio中有专门的工具来自动处理。
例,二进制及XML格式的序列化:
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;
[Serializable]
public class Person
{
public string Name {
get; set; }
public int Age {
get; set; }
public Person() {
}
public Person(string name, int age) {
this.Name = name;
this.Age = age;
}
public override string ToString() {
return Name + "(" + Age + ")";
}
}
public class SerializeDemo
{
public static void TestMain() {
Person[] people = {
new Person("李明", 18),
new Person("王强", 19),
};
// 二进制序列化
BinaryFormatter binary = new BinaryFormatter();
string fileName = "s.temp";
BinarySerialize(binary, fileName, people);
// 二进制反序列化
Person[] people1 = BinaryDeserialize(binary, fileName) as Person[];
foreach (Person p in people1)
Console.WriteLine(p);
// XML序列化
XmlSerializer xmlser = new XmlSerializer(typeof(Person[]));
string xmlFileName = "s.xml";
XmlSerializer(xmlser, xmlFileName, people);
// 显示XML文本
string xml = File.ReadAllText(xmlFileName);
Console.WriteLine(xml);
}
private static void BinarySerialize(IFormatter formatter, string fileName, object obj) {
FileStream fs = new FileStream(fileName, FileMode.Create);
formatter.Serialize(fs, obj);
fs.Close();
}
private static object BinaryDeserialize(IFormatter formatter, string fileName) {
FileStream fs = new FileStream(fileName, FileMode.Open);
object obj = formatter.Deserialize(fs);
fs.Close();
return obj;
}
private static void XmlSerializer(XmlSerializer ser, string fileName, object obj) {
FileStream fs = new FileStream(fileName, FileMode.Create);
ser.Serialize(fs, obj);
fs.Close();
}
}
运行结果:
李明(18)
王强(19)
<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Person>
<Name>李明</Name>
<Age>18</Age>
</Person>
<Person>
<Name>王强</Name>
<Age>19</Age>
</Person>
</ArrayOfPerson>