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

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

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

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

    }内存流的基本使用方法:
    private 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);
    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();
    }打开文件并读取内容:
    private 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:ook.dat", FileMode.Create))
       {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(fs, book);
       }

       book = null;

       using(FileStream fs = new FileStream(@"C:ook.dat", FileMode.Open))
       {
        BinaryFormatter formatter = new BinaryFormatter();
        book = (Book)formatter.Deserialize(fs);//在这里大家要注意咯,他的返回值是object
       }
      }
  • 相关阅读:
    【反射】Java反射机制
    Composer教程之常用命令
    Composer教程之基础用法
    Composer教程之初识Composer
    Composer 的结构详解
    现代 PHP 新特性系列(七) —— 内置的 HTTP 服务器
    现代 PHP 新特性系列(一) —— 命名空间
    现代 PHP 新特性系列(二) —— 善用接口
    现代 PHP 新特性系列(三) —— Trait 概览
    现代 PHP 新特性系列(四) —— 生成器的创建和使用
  • 原文地址:https://www.cnblogs.com/chengcailian/p/3836436.html
Copyright © 2011-2022 走看看