.Net 文件流 System.IO之Stream

转自 :http://www.cnblogs.com/yukaizhao/archive/2011/07/28/stream.html

 

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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就是实实在在的异步操作了。

如下示例代码和注释:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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对象,然后向内存流中写入一个字节数组

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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();
             }
         }
     }
}

转载于:https://www.cnblogs.com/IT-Bear/archive/2013/01/18/2865848.html

你可能感兴趣的:(.Net 文件流 System.IO之Stream)