可以借助另一項技術把數據保存到文件--序列化。序列化是一個基於 .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 的數據壓縮。