黑马程序员技术交流社区

标题: .NET 文件流详解:System.IO之Stream [打印本页]

作者: 郑昱曦    时间: 2012-11-14 14:14
标题: .NET 文件流详解:System.IO之Stream
本帖最后由 郑昱曦 于 2012-11-14 14:16 编辑

Stream在msdn的定义:提供字节序列的一般性视图(provides a generic view of a sequence of bytes)。这个解释太抽象了,不容易理解;从stream的字面意思“河,水流”更容易理解些,stream是一个抽象类,它定义了类似“水流”的事物的一些统一行为,包括这个“水流”是否可以抽水出来(读取流内容);是否可以往这个“水流”中注水(向流中写入内容);以及这个“水流”有多长;如何关闭“水流”,如何向“水流”中注水,如何从“水流”中抽水等“水流”共有的行为。

  常用的Stream的子类有:

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

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

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

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

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

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

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;

  6. namespace UseStream
  7. {
  8.     class Program
  9.     {
  10.         //示例如何从流中读取字节流
  11.         static void Main(string[] args)
  12.         {
  13.             var bytes = new byte[] {(byte)1,(byte)2,(byte)3,(byte)4,(byte)5,(byte)6,(byte)7,(byte)8};
  14.             using (var memStream = new MemoryStream(bytes))
  15.             {
  16.                 int offset = 0;
  17.                 int readOnce = 4;
  18.                  
  19.                 do
  20.                 {
  21.                     byte[] byteTemp = new byte[readOnce];
  22.                     // 使用Read方法从流中读取字节
  23.                     //第一个参数byte[]存储从流中读出的内容
  24.                     //第二个参数为存储到byte[]数组的开始索引,
  25.                     //第三个int参数为一次最多读取的字节数
  26.                     //返回值是此次读取到的字节数,此值小于等于第三个参数
  27.                     int readCn = memStream.Read(byteTemp, 0, readOnce);
  28.                     for (int i = 0; i < readCn; i++)
  29.                     {
  30.                         Console.WriteLine(byteTemp[i].ToString());
  31.                     }
  32.                      
  33.                     offset += readCn;

  34.                     //当实际读取到的字节数小于设定的读取数时表示到流的末尾了
  35.                     if (readCn < readOnce) break;
  36.                 } while (true);
  37.             }

  38.             Console.Read();
  39.         }
  40.     }
  41. }<span style="background-color: white; color: rgb(0, 0, 0); font-family: SimSun; font-size: 14px; line-height: 23px;"> </span>
复制代码

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

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

  如下示例代码和注释:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using System.Threading;

  7. namespace UseBeginRead
  8. {
  9.     class Program
  10.     {
  11.         //定义异步读取状态类
  12.         class AsyncState
  13.         {
  14.             public FileStream FS { get; set; }

  15.             public byte[] Buffer { get; set; }

  16.             public ManualResetEvent EvtHandle { get; set; }
  17.         }

  18.         static  int bufferSize = 512;

  19.         static void Main(string[] args)
  20.         {
  21.             string filePath = "d:\\test.txt";
  22.             //以只读方式打开文件流
  23.             using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
  24.             {
  25.                 var buffer = new byte[bufferSize];

  26.                 //构造BeginRead需要传递的状态
  27.                 var asyncState = new AsyncState { FS = fileStream, Buffer = buffer ,EvtHandle = new ManualResetEvent(false)};

  28.                 //异步读取
  29.                 IAsyncResult asyncResult = fileStream.BeginRead(buffer, 0, bufferSize, new AsyncCallback(AsyncReadCallback), asyncState);

  30.                 //阻塞当前线程直到读取完毕发出信号
  31.                 asyncState.EvtHandle.WaitOne();
  32.                 Console.WriteLine();
  33.                 Console.WriteLine("read complete");
  34.                 Console.Read();
  35.             }
  36.         }

  37.         //异步读取回调处理方法
  38.         public static void AsyncReadCallback(IAsyncResult asyncResult)
  39.         {
  40.             var asyncState = (AsyncState)asyncResult.AsyncState;
  41.             int readCn = asyncState.FS.EndRead(asyncResult);
  42.             //判断是否读到内容
  43.             if (readCn > 0)
  44.             {
  45.                 byte[] buffer;
  46.                 if (readCn == bufferSize) buffer = asyncState.Buffer;
  47.                 else
  48.                 {
  49.                     buffer = new byte[readCn];
  50.                     Array.Copy(asyncState.Buffer, 0, buffer, 0, readCn);
  51.                 }

  52.                 //输出读取内容值
  53.                 string readContent = Encoding.UTF8.GetString(buffer);
  54.                  
  55.                 Console.Write(readContent);
  56.             }

  57.             if (readCn < bufferSize)
  58.             {
  59.                 asyncState.EvtHandle.Set();
  60.             }
  61.             else {
  62.                 Array.Clear(asyncState.Buffer, 0, bufferSize);
  63.                 //再次执行异步读取操作
  64.                 asyncState.FS.BeginRead(asyncState.Buffer, 0, bufferSize, new AsyncCallback(AsyncReadCallback), asyncState);
  65.             }
  66.         }
  67.     }
  68. }
复制代码

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

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

  1. using System;

  2.   using System.Collections.Generic;

  3.   using System.Linq;

  4.   using System.Text;

  5.   using System.IO;

  6.   namespace UseStreamWrite

  7.   {

  8.   class Program

  9.   {

  10.   static void Main(string[] args)

  11.   {

  12.   using (var ms = new MemoryStream())

  13.   {

  14.   int count = 20;

  15.   var buffer = new byte[count];

  16.   for (int i = 0; i < count; i++)

  17.   {

  18.   buffer[i] = (byte)i;

  19.   }

  20.   //将流当前位置设置到流的起点

  21.   ms.Seek(0, SeekOrigin.Begin);

  22.   Console.WriteLine("ms position is " + ms.Position);

  23.   //注意在调用Stream的Write方法之前要用CanWrite判断Stream是否可写

  24.   if (ms.CanWrite)

  25.   {

  26.   ms.Write(buffer, 0, count);

  27.   }

  28.   //正确写入的话,流的位置会移动到写入开始位置加上写入的字节数

  29.   Console.WriteLine("ms position is " + ms.Position);

  30.   }

  31.   Console.Read();

  32.   }

  33.   }

  34.   }
复制代码

作者: 许庭洲    时间: 2012-11-14 20:56
值得学习ing!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2