System.IO 二
接着上篇的来 System.IO
FileSystemWatcher
指向这个签名的方法
可以监听目录发生了什么事件
例如:
static void Main(string[] args) { Console.WriteLine("请开始你的表演:"); FileSystemWatcher watcher = new FileSystemWatcher(); watcher.Path = @"E:\Test"; //此目录一定需要存在,不然会引发 ArgumentException 异常 //设置需要 留意 的事情 watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; //只观察文本文件 watcher.Filter = "*.txt"; //添加事件处理程序 watcher.Changed += new FileSystemEventHandler(Onchange); watcher.Created += new FileSystemEventHandler(Onchange); watcher.Deleted += new FileSystemEventHandler(Onchange); watcher.Renamed += new RenamedEventHandler(OnRenamed); //开始观察目录 watcher.EnableRaisingEvents = true; //等待用户退出程序 Console.WriteLine("请按 `q` 退出程序"); while (Console.Read() !='q'); } static void Onchange(object source, FileSystemEventArgs e) { //指定当文件改变、创建或者删除的时候需要做的事情 Console.WriteLine("File:{0} {1}",e.FullPath,e.ChangeType); } static void OnRenamed(object source, RenamedEventArgs e) { //指定当文件重命名的时候需要做的事情 Console.WriteLine("File: {0} renamed to {1}",e.OldFullPath,e.FullPath); }
对象序列化
序列化描述了持久化一个对象的状态到流(如文件流和内存流)的过程。序列化服务保存应用程序数据相对于IO命名空间的读读取器/编写器,减少了很多的麻烦。
在看列子之前,你先要理解一个类。
[Serializable] //序列化的对象需要标记为可以序列化 public class UserProp { public string WindowColor; public int FontSize; } Console.WriteLine("请开始你的表演:"); UserProp userData = new UserProp(); userData.WindowColor = "red"; userData.FontSize = 50; //将一个对象保存到一个本地 BinaryFormatter binFormat = new BinaryFormatter(); using (Stream fStrem=new FileStream("Haha.txt", FileMode.Create, FileAccess.Write, FileShare.None)) { binFormat.Serialize(fStrem,userData); //将对象序列化为流 } Console.ReadLine();
虽然对象序列化保存对象非常简单,单幕后的调用过程非常复杂。除了保存为二进制格式外还可以保存为简单对象访问协议(SOAP)或XML格式。
最后要知道对象图可以持久化为任意的System.IO.Stream派生类型。
一组关联对象(包括基类和派生类)被总称为一个对象图。对象图提供一种很简明的方式来记载一组对象如何相互引用对方。
为序列化配置对象
为每个一个关联 的类(或结构)加上 [serializable] 特性,不参与到序列化配置中,可以在这么域前面加上 [NoSerialized]特性。
定义可序列化对象
[Serializable] public class Radio { public bool hasTweeters; public bool hasSubWoofers; [NonSerialized] //把此变量设置为不可序列化的 public string radioID = "X-Y110"; } [Serializable] public class Car { public Radio theRadio = new Radio(); public bool isHatchBack; } [Serializable] public class JamesBondCar : Car { public bool canFly; public bool canSubmerge; }
注:[Serializable]特性不能被继承。因此,如果从被标记为[Serializable]的类派生一个类,子类也必须被标记为[Serializable],否则它不能持久化。
有一句话叫做公共的属性,私有的字段
一般的情况,是在一个类中,我们把字段定义为私有的,属性则定义为公共的。这句的来源则是我们在一个类中声明一个字段,然后把这个字段进行重构,封装字段。
[Serializable] public class Person { //公共字段 public bool isAlive = true; //私有字段 private int personAge = 21; //公共属性,私有字段 private string fName; public string FName { get { return fName; } set { fName = value; } }
我们使用 BinaryFormatter或 SoapFormatter进行处理,都可以保存到所选的流中。然而,XmLSerializer不会保存personAge的值。
序列化格式方法
一旦将类型配置为参与.NET序列化,接下来就是选择当持久化对象图时使用哪种格式(二进制、SOAP或XML),有以下3中选择:
BinaryFormatter:
SoapFormatter:
XmlSerializer:
在引用不出命名空间的时候请去引用里面添加引用。
第一个上面说过了,是二进制格式。
这里我们可以了解下它的属性和方法,主要是序列化和反序列化的方法。SOAP是一个标准的XML格式。
有很的重载构造函数。
下面会介绍如何使用这三种格式序列化对象。
这三个都市直接派生于System.Object.
IFormatter和IremotingFormatting接口
我们来看看IFormatter接口
它们两个类继承同一个接口,而此接口中这两个主要的方法刚好符合我们的要求 。所有我们建立一个方法使用这两个类中的一个来序列化一个对象图。
/// <summary> /// 两个类的通用方法 /// </summary> /// <param name="itfFormat">BinaryFormatter或SoapFormatter的实例</param> /// <param name="destStrem">准备的Stream流</param> /// <param name="graph">需要写的序列化对象</param> static void SerializeObjectGraph(IFormatter itfFormat, Stream destStrem, object graph) { itfFormat.Serialize(destStrem,graph); }
在格式化程序中的类型保真
在3种格式化程序中,最明显不同是对象图被持久化为不同的流(二进制、SOAP或XML)的方式。BinaryFormatter在希望用值(例如以一个完整的副本)跨越.NET应用程序机器边界传递对象时成为理想的选择。当希望尽可能延伸持久化对象图的使用范围时,SoapFormatter和XmlSerializer是理想选择。
①使用BinaryFormatter序列化对象
Ⅰ Serialize():将一个对象图按字节顺序转化为一个对象图。
Ⅱ Deserialize():讲一个持久化的字节顺序转化为一个对象图。
static void Main(string[] args) { Console.WriteLine("请开始你的表演:"); JamesBondCar jbc = new JamesBondCar(); jbc.canFly = true; jbc.canSubmerge = false; jbc.theRadio.stationPresets = new double[] { 89.3, 105.1, 97.1 }; jbc.theRadio.hasTweeters = true; //以二进制格式保存car SaveAsBinaryFormat(jbc,"CarDara.dat"); Console.ReadLine(); } static void SaveAsBinaryFormat(object objGraph, string fileName) { BinaryFormatter binFormat = new BinaryFormatter(); using (Stream fStream=new FileStream(fileName,FileMode.Create,FileAccess.Write,FileShare.None)) { binFormat.Serialize(fStream, objGraph); } Console.WriteLine("保存成功了"); }
使用BinaryFormatter反序列化对象,SOAP和XML反序列化类似
/// <summary> /// 反序列化 /// </summary> /// <param name="fileName">文件名</param> static void LoadFormBinaryFile(string fileName) { BinaryFormatter binFormat = new BinaryFormatter(); using (Stream fStream=File.OpenRead(fileName)) { JamesBondCar carFormDisk =(JamesBondCar)binFormat.Deserialize(fStream); //Deserialize返回的是object类型,转下型然后接收就可以了 Console.WriteLine("fly属性:{0}",carFormDisk.canFly); } }
②使用SoapFprmatter序列化对象
static void SaveAsSoapFormat(object objGraph,string fileName) { SoapFormatter soapFomat = new SoapFormatter(); using (Stream fStream=new FileStream(fileName,FileMode.Create,FileAccess.Write,FileShare.None)) { soapFomat.Serialize(fStream,objGraph); } Console.WriteLine("保存Soap格式成功"); }
③使用XmlSerializer序列化对象
static void SaveAsXmlFormat(object objGraph, string fileName) { //此类的构成函数必须给参数,需要确定你对谁进行序列化 XmlSerializer xmlFormat = new XmlSerializer(typeof(JamesBondCar)); using (Stream fStream=new FileStream(fileName,FileMode.Create,FileAccess.Write,FileShare.None)) { xmlFormat.Serialize(fStream,objGraph); } Console.WriteLine("序列化XML完成"); }
XmlSerializer要求对象图中的所有序列化类型支持默认的构造函数。没有的话需要加上
上面三种可以看出,XML格式是最清楚和简单的。
控制生成的XML数据
System.Xml.Serialization命名空间中的部分特性
例如:
如果想更深一点的了解可以去官网查看
序列化对象集合
前面已经演示了如何将一个对象持久化为一个流,下面演示如何保存一组对象。
一组对象就需要用到集合了。(数组、ArrayList或List<T>)。用数组代替我们之前用的单个对象就可以了
List<JamesBondCar> myCars = new List<JamesBondCar>() { new JamesBondCar(){ canFly=true, canSubmerge=false, isHatchBack=false}, new JamesBondCar(){ canFly=true, canSubmerge=true, isHatchBack=false}, new JamesBondCar(){ canFly=true, canSubmerge=false, isHatchBack=true}, }; //以二进制格式保存car // SaveAsBinaryFormat(jbc, "CarDara.dat"); // LoadFormBinaryFile("CarDara.dat"); //SaveAsSoapFormat(jbc,"CarData.soap"); SaveAsXmlFormat(myCars,"CarData.xml"); Console.ReadLine();
static void SaveAsXmlFormat(List<JamesBondCar> objGraph, string fileName) { //此类的构成函数必须给参数,需要确定你对谁进行序列化 XmlSerializer xmlFormat = new XmlSerializer(typeof(List<JamesBondCar>)); using (Stream fStream=new FileStream(fileName,FileMode.Create,FileAccess.Write,FileShare.None)) { xmlFormat.Serialize(fStream,objGraph); } Console.WriteLine("序列化XML完成"); }
另外两个类似。
自定义Soap/Binary序列化过程
System.Runtime.Serizlization命名空间核心类型
深入了解对象序列化
当BinaryFormatter序列化一个对象图时,它负责传送下面的信息到指定的流。
①在对象图中对象的完全限定名(如 MyApp.Car)
②定义对象图的程序名称(如 MyApp.exe)
③SerizlizationInfo 类的一个实例,包含了所有由对象图成员保存的所有描述性数据
SoapFormatter也类似。
使用ISerizlizable自定义序列化
被标记了[Serializable]的对象拥有了实现ISerializable接口的选项。
这个接口就一个方法:
AddValue这个重载很多。
实现了ISerizlizable接口的类型也必须定义一个带有下面签名的特殊构造函数:
例如:
[Serializable] public class StringData : ISerializable { private string dataItemOne = "First data block"; private string dataItemTwo = "More data"; public StringData() { } protected StringData(SerializationInfo si,StreamingContext ctx) { //从流中得到合并的成员变量 dataItemOne = si.GetString("First_Item").ToLower(); dataItemTwo = si.GetString("dataItemTwo").ToLower(); } public void GetObjectData(SerializationInfo info, StreamingContext context) { //用格式化数据填充SerizlizationInfo对象 info.AddValue("First_Item", dataItemOne.ToUpper()); info.AddValue("dataItemTwo", dataItemTwo.ToUpper()); } }
StringData myData = new StringData(); SoapFormatter soapFprmat = new SoapFormatter(); using (Stream fStream=new FileStream("MyData.soap",FileMode.Create,FileAccess.Write,FileShare.None)) { soapFprmat.Serialize(fStream,myData); }
可以简单的完成
[OnSerializing] private void OnSerializing(StreamingContext context) //需要带上此参数 { //在序列化的过程就调用 dataItemOne = dataItemOne.ToUpper(); dataItemTwo = dataItemTwo.ToUpper(); } [OnDeserialized] private void OnDeserialized(StreamingContext context) { //在反序列化的过程就调用 dataItemOne = dataItemOne.ToLower(); dataItemTwo = dataItemTwo.ToLower(); }
这个命名空间介绍完了,涉及的类有点多。。。