文件和流(序列化)

       可以借助另一项技术把数据保存到文件--序列化。序列化是一个基于 .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 的数据压缩。

posted on 2012-08-21 10:56  SkySoot  阅读(3676)  评论(0编辑  收藏  举报

导航