文件和流(序列化)
可以借助另一项技术把数据保存到文件--序列化。序列化是一个基于 .NET 流的高层模型。就本质而言,序列化允许你把整个活动的对象转换为一系列字节,并把这些字节写入 FileStream 之类的流对象中。以后,你可以重新读取这些字节从而重建原对象。
你的类必须符合下列条件才能使用序列化:
- 在类的声明前必须有 Serializable 特性
- 类的所有公有和私有变量必须是可序列化的
- 如果该类从其他类继承,所有的父类都必须可序列化
如果你违反任一规则,在你序列化对象时会得到一个 SerializationException 异常。
下面是一个可用于保存日志信息的可序列化类:
[Serializable]
public class LogEntry
{
public string Message { get; set; }
public DateTime Date { get; set; }
public LogEntry(string message)
{
this.Message = message;
this.Date = DateTime.Now;
}
}
提示:
类使可以包含不需要序列的数据的,例如某个大型字段可以很方便的重建或者出于安全性的考虑。遇到这些情况,在恰当的变量前加入 NonSerialized 特性即可。反序列化数据以创建原对象的副本时,不可序列化的变量会返回它们的默认值。
要把可序列化对象转换为字节流,必须使用一个实现 IFormatter 接口的类。
.NET Framework 包含两个这样的类:
- BinaryFormatter:把对象序列化成压缩的二进制格式。(位于 System.Runtime.Serialization.Formatters.Binary 命名空间)
- SoapFormatter:使用 SOAP XML 格式产生一个相对长一些的基于文本的信息。(位于 System.Runtime.Serialization.Formatters.Soap 命名空间,同时还需要先引用程序集 System.Runtime.Serialization.Formatters.Soap.dll )
以先前的示例为基础加以修改,看一下怎么序列化对象:
private void Log(string message)
{
FileMode mode;
if (ViewState["LogFile"] == null)
{
ViewState["LogFile"] = GetFileName();
mode = FileMode.Create;
}
else
{
mode = FileMode.Append;
}
string fileName = ViewState["LogFile"].ToString();
using (FileStream fs = new FileStream(fileName, mode))
{
LogEntry entry = new LogEntry(message);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, entry);
}
}
不再读取原始数据,现在反序列化每个保存的实例:
protected void btnRead_Click(object sender, EventArgs e)
{
if (ViewState["LogFile"] != null)
{
StringBuilder log = new StringBuilder();
string fileName = ViewState["LogFile"].ToString();
using (FileStream fs = new FileStream(fileName, FileMode.Open))
{
BinaryFormatter formatter = new BinaryFormatter();
// 文件中被序列化的对象有多个,因此要用循环
while (fs.Position < fs.Length)
{
// 每一次反序列化出一个对象,流中的位置(Position)都会前进到下一个对象前
LogEntry entry = (LogEntry)formatter.Deserialize(fs);
log.Append(entry.Date.ToString());
log.Append("<br />");
log.Append(entry.Message);
log.Append("<br /><br />");
}
}
lblInfo.Text = log.ToString();
}
else
{
lblInfo.Text = "There is no log file";
}
}
总结:
至此,文件和流这一部分讲述了如何利用 .NET 类来获取文件系统信息,如何使用文件和序列化对象,还讲述了数据绑定如何与文件类一起工作,如何用 Path 类弥补安全漏洞,如何处理多用户场景里对文件资源的争夺,最后,还说了使用 GZIP 的数据压缩。