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方法从流中读取字节,如下示例注释:
| 01 | usingSystem;  | 
| 02 | usingSystem.Collections.Generic;  | 
| 03 | usingSystem.Linq;  | 
| 04 | usingSystem.Text;  | 
| 05 | usingSystem.IO;  | 
| 06 |   | 
| 07 | namespaceUseStream  | 
| 08 | {  | 
| 09 |     classProgram  | 
| 10 |     {  | 
| 11 |         //示例如何从流中读取字节流  | 
| 12 |         staticvoidMain(string[] args)  | 
| 13 |         {  | 
| 14 |             var bytes = newbyte[] {(byte)1,(byte)2,(byte)3,(byte)4,(byte)5,(byte)6,(byte)7,(byte)8};  | 
| 15 |             using(var memStream = newMemoryStream(bytes))  | 
| 16 |             {  | 
| 17 |                 intoffset = 0;  | 
| 18 |                 intreadOnce = 4;  | 
| 19 |                   | 
| 20 |                 do | 
| 21 |                 {  | 
| 22 |                     byte[] byteTemp = newbyte[readOnce];  | 
| 23 |                     // 使用Read方法从流中读取字节  | 
| 24 |                     //第一个参数byte[]存储从流中读出的内容  | 
| 25 |                     //第二个参数为存储到byte[]数组的开始索引,  | 
| 26 |                     //第三个int参数为一次最多读取的字节数  | 
| 27 |                     //返回值是此次读取到的字节数,此值小于等于第三个参数  | 
| 28 |                     intreadCn = memStream.Read(byteTemp, 0, readOnce);  | 
| 29 |                     for(inti = 0; i < readCn; i++)  | 
| 30 |                     {  | 
| 31 |                         Console.WriteLine(byteTemp[i].ToString());  | 
| 32 |                     }  | 
| 33 |                       | 
| 34 |                     offset += readCn;  | 
| 35 |   | 
| 36 |                     //当实际读取到的字节数小于设定的读取数时表示到流的末尾了  | 
| 37 |                     if(readCn < readOnce) break;  | 
| 38 |                 } while(true);  | 
| 39 |             }  | 
| 40 |   | 
| 41 |             Console.Read();  | 
| 42 |         }  | 
| 43 |     }  | 
| 44 | } | 
2. 使用Stream.BeginRead方法读取FileStream的流内容
注意:BeginRead在一些流中的实现和Read完全相同,比如MemoryStream;而在FileStream和NetwordStream中BeginRead就是实实在在的异步操作了。
如下示例代码和注释:
| 01 | usingSystem;  | 
| 02 | usingSystem.Collections.Generic;  | 
| 03 | usingSystem.Linq;  | 
| 04 | usingSystem.Text;  | 
| 05 | usingSystem.IO;  | 
| 06 | usingSystem.Threading;  | 
| 07 |   | 
| 08 | namespaceUseBeginRead  | 
| 09 | {  | 
| 10 |     classProgram  | 
| 11 |     {  | 
| 12 |         //定义异步读取状态类  | 
| 13 |         classAsyncState  | 
| 14 |         {  | 
| 15 |             publicFileStream FS { get; set; }  | 
| 16 |   | 
| 17 |             publicbyte[] Buffer { get; set; }  | 
| 18 |   | 
| 19 |             publicManualResetEvent EvtHandle { get; set; }  | 
| 20 |         }  | 
| 21 |   | 
| 22 |         staticintbufferSize = 512;  | 
| 23 |   | 
| 24 |         staticvoidMain(string[] args)  | 
| 25 |         {  | 
| 26 |             stringfilePath = "d:\\test.txt";  | 
| 27 |             //以只读方式打开文件流  | 
| 28 |             using(var fileStream = newFileStream(filePath, FileMode.Open, FileAccess.Read))  | 
| 29 |             {  | 
| 30 |                 var buffer = newbyte[bufferSize];  | 
| 31 |   | 
| 32 |                 //构造BeginRead需要传递的状态  | 
| 33 |                 var asyncState = newAsyncState { FS = fileStream, Buffer = buffer ,EvtHandle = newManualResetEvent(false)};  | 
| 34 |   | 
| 35 |                 //异步读取  | 
| 36 |                 IAsyncResult asyncResult = fileStream.BeginRead(buffer, 0, bufferSize, newAsyncCallback(AsyncReadCallback), asyncState);  | 
| 37 |   | 
| 38 |                 //阻塞当前线程直到读取完毕发出信号  | 
| 39 |                 asyncState.EvtHandle.WaitOne();  | 
| 40 |                 Console.WriteLine();  | 
| 41 |                 Console.WriteLine("read complete");  | 
| 42 |                 Console.Read();  | 
| 43 |             }  | 
| 44 |         }  | 
| 45 |   | 
| 46 |         //异步读取回调处理方法  | 
| 47 |         publicstaticvoidAsyncReadCallback(IAsyncResult asyncResult)  | 
| 48 |         {  | 
| 49 |             var asyncState = (AsyncState)asyncResult.AsyncState;  | 
| 50 |             intreadCn = asyncState.FS.EndRead(asyncResult);  | 
| 51 |             //判断是否读到内容  | 
| 52 |             if(readCn > 0)  | 
| 53 |             {  | 
| 54 |                 byte[] buffer;  | 
| 55 |                 if(readCn == bufferSize) buffer = asyncState.Buffer;  | 
| 56 |                 else | 
| 57 |                 {  | 
| 58 |                     buffer = newbyte[readCn];  | 
| 59 |                     Array.Copy(asyncState.Buffer, 0, buffer, 0, readCn);  | 
| 60 |                 }  | 
| 61 |   | 
| 62 |                 //输出读取内容值  | 
| 63 |                 stringreadContent = Encoding.UTF8.GetString(buffer);  | 
| 64 |                   | 
| 65 |                 Console.Write(readContent);  | 
| 66 |             }  | 
| 67 |   | 
| 68 |             if(readCn < bufferSize)  | 
| 69 |             {  | 
| 70 |                 asyncState.EvtHandle.Set();  | 
| 71 |             }  | 
| 72 |             else{  | 
| 73 |                 Array.Clear(asyncState.Buffer, 0, bufferSize);  | 
| 74 |                 //再次执行异步读取操作  | 
| 75 |                 asyncState.FS.BeginRead(asyncState.Buffer, 0, bufferSize, newAsyncCallback(AsyncReadCallback), asyncState);  | 
| 76 |             }  | 
| 77 |         }  | 
| 78 |     }  | 
| 79 | } | 
3. 使用Stream.Write方法向流中写字节数组
在使用Write方法时,需要先使用Stream的CanWrite方法判断流是否可写,如下示例定义了一个MemoryStream对象,然后向内存流中写入一个字节数组
| 01 | usingSystem;  | 
| 02 | usingSystem.Collections.Generic;  | 
| 03 | usingSystem.Linq;  | 
| 04 | usingSystem.Text;  | 
| 05 | usingSystem.IO;  | 
| 06 |   | 
| 07 | namespaceUseStreamWrite  | 
| 08 | {  | 
| 09 |     classProgram  | 
| 10 |     {  | 
| 11 |         staticvoidMain(string[] args)  | 
| 12 |         {  | 
| 13 |             using(var ms = newMemoryStream())  | 
| 14 |             {  | 
| 15 |                 intcount = 20;  | 
| 16 |                 var buffer = newbyte[count];  | 
| 17 |                 for(inti = 0; i < count; i++)  | 
| 18 |                 {  | 
| 19 |                     buffer[i] = (byte)i;  | 
| 20 |                 }  | 
| 21 |   | 
| 22 |                 //将流当前位置设置到流的起点  | 
| 23 |                 ms.Seek(0, SeekOrigin.Begin);  | 
| 24 |   | 
| 25 |                 Console.WriteLine("ms position is "+ ms.Position);  | 
| 26 |   | 
| 27 |                 //注意在调用Stream的Write方法之前要用CanWrite判断Stream是否可写  | 
| 28 |                 if(ms.CanWrite)  | 
| 29 |                 {  | 
| 30 |                     ms.Write(buffer, 0, count);  | 
| 31 |                 }  | 
| 32 |   | 
| 33 |                 //正确写入的话,流的位置会移动到写入开始位置加上写入的字节数  | 
| 34 |                 Console.WriteLine("ms position is "+ ms.Position);  | 
| 35 |   | 
| 36 |             }  | 
| 37 |   | 
| 38 |             Console.Read();  | 
| 39 |         }  | 
| 40 |     }  | 
| 41 | }  | 
4. 使用Stream.BeginWrite方法异步写;异步写可以提高程序性能,这是因为磁盘或者网络IO的速度远小于cpu的速度,异步写可以减少cpu的等待时间。
如下使用FileStream异步写文件的操作示例
| usingSystem;  | 
| usingSystem.Collections.Generic;  | 
| usingSystem.Linq;  | 
| usingSystem.Text;  | 
| usingSystem.IO;  | 
| usingSystem.Threading;  | 
|   | 
| namespaceUseStreamBeginWrite  | 
| {  | 
|     classProgram  | 
|     {  | 
|         /// <summary>  | 
|         /// 异步回调需要的参数封装类  | 
|         /// </summary>  | 
|         classAsyncState {  | 
|             publicintWriteCountOnce { get; set; }  | 
|   | 
|             publicintOffset { get; set; }  | 
|   | 
|             publicbyte[] Buffer { get; set; }  | 
|   | 
|             publicManualResetEvent WaitHandle { get; set; }  | 
|   | 
|             publicFileStream FS { get; set; }  | 
|         }  | 
|   | 
|         staticvoidMain(string[] args)  | 
|         {  | 
|             //准备一个1K的字节数组  | 
|             byte[] toWriteBytes = newbyte[1 << 10];  | 
|             for(inti = 0; i < toWriteBytes.Length; i++)  | 
|             {  | 
|                 toWriteBytes[i] = (byte)(i % byte.MaxValue);  | 
|             }  | 
|   | 
|             stringfilePath = "d:\\test.txt";  | 
|             //FileStream实例  | 
|             using(var fileStream = newFileStream(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))  | 
|             {   | 
|                 intoffset = 0;  | 
|                 //每次写入32字节  | 
|                 intwriteCountOnce = 1 << 5;  | 
|   | 
|                 //构造回调函数需要的状态  | 
|                 AsyncState state = newAsyncState{  | 
|                     WriteCountOnce = writeCountOnce,  | 
|                     Offset = offset,  | 
|                     Buffer = toWriteBytes,  | 
|                     WaitHandle = newManualResetEvent(false),  | 
|                     FS = fileStream  | 
|                 };  | 
|   | 
|                 //做异步写操作  | 
|                 fileStream.BeginWrite(toWriteBytes, offset, writeCountOnce, WriteCallback, state);  | 
|   | 
|                 //等待写完毕或者出错发出的继续信号  | 
|                 state.WaitHandle.WaitOne();  | 
|             }  | 
|   | 
|             Console.WriteLine("Done");  | 
|   | 
|             Console.Read();  | 
|         }  | 
|   | 
|         /// <summary>  | 
|         /// 异步写的回调函数  | 
|         /// </summary>  | 
|         /// <param name="asyncResult">写状态</param>  | 
|         staticvoidWriteCallback(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();  | 
|             }  | 
|         }  | 
|     }  | 
| } | 
 
                    
                     
                    
                 
                    
                 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号