zoukankan      html  css  js  c++  java
  • C# MemoryStream和BinaryFormatter

    编程访问文件是通过文件流对象进行的,当应用程序需要访问文件时,必须先创建一个文件流对象,此流对象和文件是一一对应关系。
    在.NET中,使用抽象基类System.IO.Stream代表流,它提供Read和Write两个方法。由于数据流的有序性,因此流对象还有一个读写指针,为此,Stream类还有一个Seek方法用于移动读写指针。
    FileStream对象的数据来自文件,而MemoryStream对象的数据来自内存缓冲区。这两个类都继承自Stream类。

    1.MemoryStream
    MemoryStream的数据来自内存中的一块连续区域,这块区域称为“缓冲区(Buffer)”。可以把缓冲区看成一个数组,每个数组元素可以存放一个字节的数据。

    在创建MemoryStream对象时,可以指定缓冲区的大小,并且可以在需要的时候更改。
    //字节数组
    byte[] buffer = new byte[600];
    //填充字节数组
    p rivate void CreateExampleData()
    {
          for(int i=0; i<600; i )
          {
                //byte类型的数最大不能超过255,用256取模实现
                buffer[i] = (byte)(i%256);
          }
    }

    内存流的基本使用方法:
    p rivate void OnTestMemory()
    {
          //创建测试数据
          CreateExampleData();

          //创建内存流对象,初始分配50字节的缓冲区
          MemoryStream mem = new MemoryStream(50);

          //向内存流中写入字节数组的所有数据
          mem.Write(buffer,0,buffer.GetLength(0));

          MessageBox.Show("写入数据后的内存流长度:" mem.Length.ToString());
          MessageBox.Show("分配给内存流的缓冲区大小:" mem.Capacity.ToString());

          mem.SetLength(550);

          MessageBox.Show("调用SetLength方法后的内存流长度:" mem.Length.ToString());

          mem.Capacity = 620;//此值不能小于Length属性
          MessageBox.Show("调用Capacity方法后缓冲区大小:" mem.Capacity.ToString());

          //将读写指针移到距流开头10个字节的位置
          mem.Seek(10,SeekOrigin.Begin);
          MessageBox.Show(mem.ReadByte().ToString());
          mem.Close();
     }
    内存流的Length属性代表了其中存放的数据的真实长度,而Capacity属性则代表了分配给内存流的内存空间大小。
    可以使用字节数组创建一个固定大小的MemoryStream,
    MemoryStream mem = new MemoryStream(buffer);
    这时,无法再设置Capacity属性的大小。
    还可以创建只读的内存流对象。
    MemoryStream mem = new MemoryStream(buffer,false);

    2.FileStream
    FlieStream用于存取文件。

    创建文件并写入内容:
    //创建一个新文件
    FileStream fsForWrite = new FileStream("test.data",FileMode.Create);
    try

          //写入一个字节
          fsForWrite.WriteByte(100);
          CreateExampleData();
          //将字节数组写入文件
          fsForWrite.Write(buffer,0,buffer.GetLength(0));
    }
    catch(Exception ex)

          MessageBox.Show(ex.Message);
    }
    finally
    {
          //关闭文件
          fsForWrite.Close();
    }

    打开文件并读取内容:
    p rivate void ReadFromFile()
    {
          FileStream fsForRead = new FileStream("test.data",FileMode.Open);
          try
          {
                //读入一个字节
                MessageBox.Show("文件的第一个字节为:" +fsForRead.ReadByte().ToString());
                //读写指针移到距开头10个字节处
                fsForRead.Seek(10,SeekOrigin.Begin);
                byte[] bs = new byte[10];
                //从文件中读取10个字节放到数组bs中
                fsForRead.Read(bs,0,10);
          }
          catch(Exception ex)
          { 
                MessageBox.Show(ex.Message);
          }
          finally
          {
                fsForRead.Close(); 
          }
    }

    如果一个程序退出了,但它打开的文件没有被关闭,将导致其他程序无法修改或删除此文件。
     

    //-----------------------------------------------------------------------------------------------------------------------

    BinaryFormatter序列化

    序列化简单点来理解就是把内存的东西写到硬盘中,当然也可以写到内存中(这个内容我会在后面写一个例子).而反序列化就是从硬盘中把信息读到内存中.就这么简单,呵呵,现在来看下面的例子吧!

    在这篇文章中我将使用BinaryFormatter序列化类Book作为例子,希望大家能从例子中深刻体会什么是序列化.

    定义类Book:


    [Serializable]
     public class Book
    {
      string name;
      float    price;
      string author;

      public Book(string bookname, float bookprice, string bookauthor)
     {
       name = bookname;
       price = bookprice;
       author = bookauthor;
      }
     }

    在类的上面增加了属性:Serializable.(如果不加这个属性,将抛出SerializationException异常).

    通过这个属性将Book标志为可以序列化的.当然也有另一种方式使类Book可以序列化,那就是实行ISerializable接口了.在这里大家要注意了:Serializable属性是不能被继承的咯!!!

    如果你不想序列化某个变量,该怎么处理呢?很简单,在其前面加上属性[NonSerialized] .比如我不想序列化

    string author;

    那我只需要

    [NonSerialized]

    string author;

    好了,现在就告诉大家怎么实现序列化:

    我们使用namespace:

    using System;

    using System.IO;

    using System.Runtime.Serialization.Formatters.Binary;

    首先创建Book实例,like this: 

     Book book = new Book("Day and Night", 30.0f, "Bruce");

    接着当然要创建一个文件了,这个文件就是用来存放我们要序列化的信息了.

    FileStream fs = new FileStream(@"C:\book.dat", FileMode.Create);

    序列化的实现也很简单,like this:

        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(fs, book);

    很简单吧!现在我列出整个原代码,包括反序列化.

    static void Main(string[] args)
     {
       Book book = new Book("Day and Night", 30.0f, "Bruce");

       using(FileStream fs = new FileStream(@"C:\Book.dat", FileMode.Create))
       {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(fs, book);
       }

       book = null;

       using(FileStream fs = new FileStream(@"C:\book.dat", FileMode.Open))
       {
        BinaryFormatter formatter = new BinaryFormatter();
        book = (Book)formatter.Deserialize(fs);//在这里大家要注意咯,他的返回值是object
       }
      }

  • 相关阅读:
    Win8metro外包团队:专业承接Windows 8 metro应用外包,基于HTML5、Silverlight、.NET均可
    WPF性能优化经验总结和整理综合帖
    WPF外包—WPF案例分享—WPF实现的又一个阅读器MSDN Reader
    中国已成为亚太区企业首选的外包基地
    Acer北京维修站汇总(今天电脑坏了去维修,顺便分享一下)
    WPF外包公司——北京动点飞扬软件联系方式和官方博客地址
    微软首推msnNOW服务 网络社交化风暴愈演愈烈
    WPF外包就找北京动点飞扬软件:WPF 4.5探秘之三 Dispatcher的新方法
    微软发布Windows 8标志:彰显创新回归本源(图)
    中国软件产业发展全国数据对比
  • 原文地址:https://www.cnblogs.com/hackpig/p/1668501.html
Copyright © 2011-2022 走看看