天天看点

3-8 读写内存流

u<b>本节学习目标:</b>

n了解读写内存流MemoryStream的特点

n学习如何建立内存流MemoryStream

n了解读写缓存流BufferedStream

n学习如何建立缓存流BufferedStream

前面第二节,介绍了文件流类FileStream,本节要继续介绍其他流。那么什么是流?在.net程序中,涉及的输入和输出都是通过流来实现的。流是串行化设备的抽象表示,流以读/写字节的方式从存储器读/写数据。存储器是存储媒介,磁盘或内存都是存储器。正如除磁盘外还存在着多种存储器,除文件流之外也存在多种流,例如:网络流、内存流、缓存流等。类Stream及其派生类组成流的家族。如图3-12所示:

图3-12  流家族类关系图

所有流的类都是从类Stream派生出来的。类Stream是所有流的抽象基类,所以它不能被实例化为对象,只能通过变量引用派生类的对象。Stream变量所引用对象具有一下一种或多种功能:

n读:通过Read()或ReadByte()方法实现读数据;

n写:通过Write()或WriteByte()方法实现写数据;

n定位:通过Position属性和Seek()方法实现定位。

<b></b><b></b> 

<b>注意:</b>

派生的流对象只能支持这些功能中的一部分。例如:NetworkStream不支持定位。可以利用从Stream派生出来的对象的CanRead、CanWrite和CanSeek属性判断流对象支持哪些操作。

另外,对于类MemoryStream,有两点需要说明:

n对内存而不是对磁盘进行数据读写;

n减少了对临时缓冲区和文件的需要。

而对于类BufferedStream,有四点需要说明:

n对缓冲区进行数据读写;

n允许操作系统创建自己的缓冲区;

n输入/输出效率高且速度更快;

n在网络通讯的时候经常会使用到。

类MemoryStream创建这样的流,该流以内存而不是磁盘或网络连接作为支持存储区。类MemoryStream封装以无符号字节数组形式存储的数据,该数组在创建MemoryStream对象时被初始化,或者该数组可创建为空数组。可在内存中直接访问这些封装的数据。内存流可降低应用程序中对临时缓冲区和临时文件的需要。

 FileStream对象与MemoryStream对象有很大区别,主要体现在以下方面:

nFileStream对象的数据来自文件,而MemoryStream对象的数据来自内存缓冲区。这两个类都继承自Stream类。

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

n在创建MemoryStream对象时,可以指定缓冲区的大小,并且可以在需要的时候更改。

    类MemoryStream的构造函数有7种重载,我们这里重点介绍三种,如表3-16所示:

表3-16 类MemoryStream的常用构造函数

<b>名称</b>

<b>说明</b>

MemoryStream ()

使用初始化为零的可扩展容量初始化 MemoryStream 类的新实例。

MemoryStream (byte[])

基于指定的字节数组初始化 MemoryStream 类的无法调整大小的新实例。

MemoryStream (byte[], Boolean)

使用按指定要求设置的 CanWrite 属性基于指定的字节数组初始化 MemoryStream 类的无法调整大小的新实例。

    内存流对象还有一些重要的属性。其中Length属性代表了内存流对象存放的数据的真实长度,而Capacity属性则代表了分配给内存流的内存空间大小。可以使用字节数组创建一个固定大小的MemoryStream。

n<b>小实验1:</b>

<b></b> 

MemoryStream mem = new MemoryStream(buffer);

//这时,无法再设置Capacity属性的大小。

n<b>小实验2:</b>

MemoryStream mem = new MemoryStream(buffer, false);

//这时,CanWrite属性就被设置为false 。

这样在内存流对象被实例化时,一些属性就被影响了。

本案例您将学习到:如何通过使用内存流的属性、方法来获取内存流的占用空间信息及改变内存流空间大小。

u实验步骤(1):

由图3-13所示,从工具箱之中拖拽五个Label控件到Form窗体上,拖拽一个Button控件。

图3-13  MemoryStream类案例界面图

u实验步骤(2):

用鼠标双击所有Button控件,进入.cs文件编辑状态准备进行开发。代码加下:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.IO;

namespace FileOptionApplication

{

    public partial class Form14 : Form

    {

        public Form14()

        {

            InitializeComponent();

        }

        //建立字节数组

        byte[] buffer = new byte[600];

        /// &lt;summary&gt;

        /// 获取测试性数据

        /// &lt;/summary&gt;

        private void GetTestData()

            for (int i = 0; i &lt; 600; i++)

            {

                buffer[i] = (byte)(i % 256);

                //byte类型的数最大不能超过255,用256取模实现

            }

        /// button1按钮的鼠标单击Click事件

        private void button1_Click(object sender, EventArgs e)

            //创建测试数据

            GetTestData();

            //创建内存流对象,初始分配50字节的缓冲区

            MemoryStream mem = new MemoryStream(50);

            //向内存流中写入字节数组的所有数据

            mem.Write(buffer,0,buffer.GetLength(0));

            //使用从缓冲区读取的数据将字节块写入当前流。

            //参数:

            //1、buffer从中写入数据的缓冲区。

            //2、offset buffer中的字节偏移量,从此处开始写入。

            //3、count最多写入的字节数。

            //GetLength(0) 为 GetLength 的一个示例,它返回 Array 的第一维中的元素个数。

            label1.Text = "写入数据后的内存流长度是:"+mem.Length.ToString();

            label2.Text = "分配给内存流的缓冲区大小:"+mem.Capacity.ToString();

            mem.SetLength(500);

            label3.Text = "调用SetLength方法后的内存流长度:" + mem.Length.ToString();

            mem.Capacity = 620;//注意:此值不能小于Length属性

            label4.Text = "调用Capacity方法后缓冲区大小:" + mem.Capacity.ToString();

            //将读写指针移到距流开头10个字节的位置

            mem.Seek(45, SeekOrigin.Begin);

            label5.Text = "内存中的信息是:"+mem.ReadByte().ToString();

    }

}

u实验步骤(3):

调试、运行程序,得到效果如图3-14所示:

图3-14  MemoryStream类案例运行效果图

BufferedStream也在共享缓冲区中缓冲读取和写入。假设您几乎始终执行一系列读取或写入操作,而很少在读取和写入之间切换。类BufferedStream的构造函数有2种重载,如表3-17所示:

表3-17 类BufferedStream的常用构造函数

<a>BufferedStream (Stream)</a>

使用默认的缓冲区大小 4096 字节初始化 BufferedStream 类的新实例。

<a>BufferedStream (Stream, Int32)</a>

使用指定的缓冲区大小初始化 BufferedStream 类的新实例。

本文转自 qianshao 51CTO博客,原文链接:http://blog.51cto.com/qianshao/210979,如需转载请自行联系原作者