• 热门专题

.NET 文件流学习:System.IO之Stream

作者:玉开  发布日期:2012-04-24 18:45:26
Tag标签:System.IO  Stream  
  • Streammsdn定义:提供字节序列的一般性视图(providagenerviewofasequencofbyte这个解释太抽象了不容易理解;从stream字面意思“河,水流”更容易理解些,stream一个抽象类,定义了类似“水流”事物的一些统一行为,包括这个“水流”否可以抽水进去(读取流内容);否可以往这个“水流”中注水(向流中写入内容);以及这个“水流”有多长;如何关闭“水流”如何向“水流”中注水,如何从“水流”中抽水等“水流”共有的行为。

    常用的Stream子类有:

    1MemoryStream存储在内存中的字节流

    2FileStream存储在文件系统的字节流

    3NetworkStream通过网络设备读写的字节流

    4BufferedStream为其他流提供缓冲的流

    Stream提供了读写流的方法是以字节的形式从流中读取内容。而我经常会用到从字节流中读取文本或者写入文本,微软提供了StreamRead和StreamWrit类帮我实现在流上读写字符串的功能。

    下面看下如何操作Stream即如何从流中读取字节序列,如何向流中写字节

    1.使用Stream.Read方法从流中读取字节,如下示例注释:


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    
    namespace UseStream
    {
        class Program
        {
            //示例如何从流中读取字节流
            static void Main(string[] args)
            {
                var bytes = new byte[] {(byte)1,(byte)2,(byte)3,(byte)4,(byte)5,(byte)6,(byte)7,(byte)8};
                using (var memStream = new MemoryStream(bytes))
                {
                    int offset = 0;
                    int readOnce = 4;
                     
                    do
                    {
                        byte[] byteTemp = new byte[readOnce];
                        // 使用Read方法从流中读取字节
                        //第一个参数byte[]存储从流中读出的内容
                        //第二个参数为存储到byte[]数组的开始索引,
                        //第三个int参数为一次最多读取的字节数
                        //返回值是此次读取到的字节数,此值小于等于第三个参数
                        int readCn = memStream.Read(byteTemp, 0, readOnce);
                        for (int i = 0; i < readCn; i++)
                        {
                            Console.WriteLine(byteTemp[i].ToString());
                        }
                         
                        offset += readCn;
    
                        //当实际读取到的字节数小于设定的读取数时表示到流的末尾了
                        if (readCn < readOnce) break;
                    } while (true);
                }
    
                Console.Read();
            }
        }
    }

      2. 使用Stream.BeginRead方法读取FileStream的流内容

      注意:BeginRead在一些流中的实现和Read完全相同,比如MemoryStream;而在FileStream和NetwordStream中BeginRead就是实实在在的异步操作了。

      如下示例代码和注释:


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Threading;
    
    namespace UseBeginRead
    {
        class Program
        {
            //定义异步读取状态类
            class AsyncState
            {
                public FileStream FS { get; set; }
    
                public byte[] Buffer { get; set; }
    
                public ManualResetEvent EvtHandle { get; set; }
            }
    
            static  int bufferSize = 512;
    
            static void Main(string[] args)
            {
                string filePath = "d:\\test.txt";
                //以只读方式打开文件流
                using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    var buffer = new byte[bufferSize];
    
                    //构造BeginRead需要传递的状态
                    var asyncState = new AsyncState { FS = fileStream, Buffer = buffer ,EvtHandle = new ManualResetEvent(false)};
    
                    //异步读取
                    IAsyncResult asyncResult = fileStream.BeginRead(buffer, 0, bufferSize, new AsyncCallback(AsyncReadCallback), asyncState);
    
                    //阻塞当前线程直到读取完毕发出信号
                    asyncState.EvtHandle.WaitOne();
                    Console.WriteLine();
                    Console.WriteLine("read complete");
                    Console.Read();
                }
            }
    
            //异步读取回调处理方法
            public static void AsyncReadCallback(IAsyncResult asyncResult)
            {
                var asyncState = (AsyncState)asyncResult.AsyncState;
                int readCn = asyncState.FS.EndRead(asyncResult);
                //判断是否读到内容
                if (readCn > 0)
                {
                    byte[] buffer;
                    if (readCn == bufferSize) buffer = asyncState.Buffer;
                    else
                    {
                        buffer = new byte[readCn];
                        Array.Copy(asyncState.Buffer, 0, buffer, 0, readCn);
                    }
    
                    //输出读取内容值
                    string readContent = Encoding.UTF8.GetString(buffer);
                     
                    Console.Write(readContent);
                }
    
                if (readCn < bufferSize)
                {
                    asyncState.EvtHandle.Set();
                }
                else {
                    Array.Clear(asyncState.Buffer, 0, bufferSize);
                    //再次执行异步读取操作
                    asyncState.FS.BeginRead(asyncState.Buffer, 0, bufferSize, new AsyncCallback(AsyncReadCallback), asyncState);
                }
            }
        }
    }

      3. 使用Stream.Write方法向流中写字节数组

      在使用Write方法时,需要先使用Stream的CanWrite方法判断流是否可写,如下示例定义了一个MemoryStream对象,然后向内存流中写入一个字节数组


     using System;
    
      using System.Collections.Generic;
    
      using System.Linq;
    
      using System.Text;
    
      using System.IO;
    
      namespace UseStreamWrite
    
      {
    
      class Program
    
      {
    
      static void Main(string[] args)
    
      {
    
      using (var ms = new MemoryStream())
    
      {
    
      int count = 20;
    
      var buffer = new byte[count];
    
      for (int i = 0; i < count; i++)
    
      {
    
      buffer[i] = (byte)i;
    
      }
    
      //将流当前位置设置到流的起点
    
      ms.Seek(0, SeekOrigin.Begin);
    
      Console.WriteLine("ms position is " + ms.Position);
    
      //注意在调用Stream的Write方法之前要用CanWrite判断Stream是否可写
    
      if (ms.CanWrite)
    
      {
    
      ms.Write(buffer, 0, count);
    
      }
    
      //正确写入的话,流的位置会移动到写入开始位置加上写入的字节数
    
      Console.WriteLine("ms position is " + ms.Position);
    
      }
    
      Console.Read();
    
      }
    
      }
    
      }
    
    

      4. 使用Stream.BeginWrite方法异步写;异步写可以提高程序性能,这是因为磁盘或者网络IO的速度远小于cpu的速度,异步写可以减少cpu的等待时间。

      如下使用FileStream异步写文件的操作示例


    using System;
    
      using System.Collections.Generic;
    
      using System.Linq;
    
      using System.Text;
    
      using System.IO;
    
      using System.Threading;
    
      namespace UseStreamBeginWrite
    
      {
    
      class Program
    
      {
    
      /// 
    
      /// 异步回调需要的参数封装类
    
      /// 
    
      class AsyncState {
    
      public int WriteCountOnce { get; set; }
    
      public int Offset { get; set; }
    
      public byte[] Buffer { get; set; }
    
      public ManualResetEvent WaitHandle { get; set; }
    
      public FileStream FS { get; set; }
    
      }
    
      static void Main(string[] args)
    
      {
    
      //准备一个1K的字节数组
    
      byte[] toWriteBytes = new byte[1 << 10];
    
      for (int i = 0; i < toWriteBytes.Length; i++)
    
      {
    
      toWriteBytes[i] = (byte)(i % byte.MaxValue);
    
      }
    
      string filePath = "d:\\test.txt";
    
      //FileStream实例
    
      using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
    
      {
    
      int offset = 0;
    
      //每次写入32字节
    
      int writeCountOnce = 1 << 5;
    
      //构造回调函数需要的状态
    
      AsyncState state = new AsyncState{
    
      WriteCountOnce = writeCountOnce,
    
      Offset = offset,
    
      Buffer = toWriteBytes,
    
      WaitHandle = new ManualResetEvent(false),
    
      FS = fileStream
    
      };
    
      //做异步写操作
    
      fileStream.BeginWrite(toWriteBytes, offset, writeCountOnce, WriteCallback, state);
    
      //等待写完毕或者出错发出的继续信号
    
      state.WaitHandle.WaitOne();
    
      }
    
      Console.WriteLine("Done");
    
      Console.Read();
    
      }
    
      /// 
    
      /// 异步写的回调函数
    
      /// 
    
      /// 写状态
    
      static void WriteCallback(IAsyncResult asyncResult)
    
      {
    
      AsyncState state = (AsyncState)asyncResult.AsyncState;
    
      try
    
      {
    
      state.FS.EndWrite(asyncResult);
    
      }
    
      catch (Exception ex)
    
      {
    
      Console.WriteLine("EndWrite Error:" + ex.Message);
    
      state.WaitHandle.Set();
    
      return;
    
      }
    
      Console.WriteLine("write to " + state.FS.Position);
    
      //判断是否写完,未写完继续异步写
    
      if (state.Offset + state.WriteCountOnce < state.Buffer.Length)
    
      {
    
      state.Offset += state.WriteCountOnce;
    
      Console.WriteLine("call BeginWrite again");
    
      state.FS.BeginWrite(state.Buffer, state.Offset, state.WriteCountOnce, WriteCallback, state);
    
      }
    
      else {
    
      //写完发出完成信号
    
      state.WaitHandle.Set();
    
      }
    
      }
    
      }
    
      }
    
About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规