.Net的异步机制(异步Stream读/写) - step 4

转载 2012年08月11日 21:15:32

在前面3篇文章,我已经介绍了异步的工作原理和相关方法和参数的应用.下面我们介绍Stream流的操作并使用System.IO.FileStream来揭开如何开发异步的Stream(System.IO.Stream/写操作

 

异步的Stream/写操作

 

下面是继承于System.IO.Stream的类
 System.IO
.Stream
    Microsoft.JScript.COMCharStream
    System.IO.BufferedStream
    System.IO.FileStream
    System.IO.MemoryStream
    System.IO.UnmanagedMemoryStream
    System.Security.Cryptography.CryptoStream
    System.Printing.PrintQueueStream
    System.IO.Pipes.PipeStream
    System.Data.OracleClient.OracleBFile
    System.Data.OracleClient.OracleLob
    System.IO.Compression.DeflateStream
    System.IO.Compression.GZipStream
    System.Net.Sockets.NetworkStream
    System.Net.Security.AuthenticatedStream


System.IO.Stream中提供了异步的读/(Read/Write)行为,上面继承于System.IO.Stream的类都具有同样的异步操作行为..Net Framework框架中,微软设计师使用Begin+同步方法名 / End+同步方法名来设计异步方法的规则,基本上我们在微软MSDN看到的 BeginXXX + EndXXX都是异步的方法,并且当我们在某个类中看到BeginInvoke / EndInvoke,都是微软提供的最原始的异步方法.System.IO.Stream中表现为BeginRead+EndRead / BeginWrite/EndWrite.

我们来看一个例子,FileStream(System.IO),Read / BeginRead+EndRead,读取文件内容,开始我们使用同步方法.

同步调用

Code1.1

 1static class Program
 2    {
 3        static string path = @"c:/file.txt";//确保你本地有这个文件
 4        const int bufferSize = 5;//演示,一次只读取5 byte
 5        static void Main()
 6        {
 7            FileStream fs = new FileStream(path, FileMode.Open,
 8FileAccess.Read, FileShare.Read, 20480false);//同步调用false
 9            using (fs)//使用using来释放FileStream资源
10            {
11                byte[] data = new byte[bufferSize];
12                StringBuilder sb = new StringBuilder(500);
13                int byteReads;
14                do// 不断循环,直到读取完毕
15                {
16                    byteReads = fs.Read(data, 0, data.Length);
17                    sb.Append(Encoding.ASCII.GetString(data, 0, byteReads));
18                }
 while (byteReads > 0);
19                Console.WriteLine(sb.ToString());
//输出到工作台
20
21            }
//自动清除对象资源,隐式调用fs.Close();
22            Console.ReadLine();// 让黑屏等待,不会直接关闭..
23        }

24    }

方法非常简单,它会构造一个 FileStream 对象,调用 Read方法,不断循环读取数据。C# using 语句可确保完成数据处理后会关闭该 FileStream 对象。

下面我们看异步调用(BeginRead/EndRead)

异步调用

Code1.2

 1static class Program
 2    {
 3        static string path = @"c:/file.txt";//确保你本地有这个文件
 4        const int bufferSize = 5;//演示,一次只读取5 byte
 5        static byte[] data;
 6        static void Main()
 7        {
 8            data = new byte[bufferSize];
 9            FileStream fs = new FileStream(path, FileMode.Open,
10FileAccess.Read, FileShare.Read, 20480, true);
//设置异步调用true, 注意0
11
12            //异步读取文件,把FileStream对象作为异步的参数// <-
13            AsyncCallback callback = new AsyncCallback(OnReadCompletion);
14            IAsyncResult async = fs.BeginRead(data, 0, bufferSize, callback, fs); // <-
15
16            Console.ReadLine();// 让黑屏等待,不会直接关闭..
17        }

18        static void OnReadCompletion(IAsyncResult asyncResult)
19        {
20            FileStream fs = asyncResult.AsyncState as FileStream;
21            int bytesRead = fs.EndRead(asyncResult);
22            //输出到工作台
23            Console.Write(Encoding.ASCII.GetString(data, 0, bytesRead));
24            //不断循环,直到读取完毕
25            if (bytesRead > 0)
26                fs.BeginRead(data, 0, bufferSize, OnReadCompletion, fs);
27            else
28                fs.Close(); //当全部读取完毕,显式释放资源
29        }

30    }

方法是使用BeginReadEndRead 完成的我们注意到方法不能使用 C# using 语句(释放资源),因为 FileStream是在一个主线程中打开,然后在另一个线程中关闭的,而是通过把FileStream 作为参数的形式来在另外一个线程中关闭(fs.Close();),查看红色部分.

注意0:创建FileStram 对象,如果没有FileStream fs = new FileStream(path, FileMode.Open,FileAccess.Read, FileShare.Read, 20480, true); booluseAsync=true 或者构造FileStream(String, FileMode, FileAccess, FileShare, Int32, FileOptions) FileOptions =FileOptions.Asynchronous 时,  即使使用了BeginRead/EndRead, 程序也是在同步执行方法,FileStream 对象会使用其他线程来模仿异步行为,反而降低了应用程序的性能.

 

下面我将通过使用C# 匿名方法(C# 2.0)  lambda 表达式(C# 3.0引入的一个新功能来完成上面操作,如果对这个不熟悉的朋友可以查看下面文章.

匿名方法:http://www.microsoft.com/china/msdn/library/langtool/vcsharp/CreElegCodAnymMeth.mspx?mfr=true

lambda 表达式:http://msdn.microsoft.com/zh-cn/magazine/cc163362.aspx

 

C# 匿名方法  lambda 表达式

1,匿名方法:
Code1.3

 1static class Program
 2    {
 3        static string path = @"c:/file.txt";//确保你本地有这个文件
 4        const int bufferSize = 5;//演示,一次只读取5 byte
 5        static void Main()
 6        {
 7            byte[] data = new byte[bufferSize];
 8            //[1]
 9            FileStream fs = new FileStream(path, FileMode.Open,
10FileAccess.Read, FileShare.Read, 20480true);//设置异步调用true
11            //使用匿名委托方式
12            AsyncCallback callback = null//注意1
13            callback = delegate(IAsyncResult asyncResult)//匿名方法
14            {
15                int bytesRead = fs.EndRead(asyncResult);//[2]
16                Console.Write(Encoding.ASCII.GetString(data, 0, bytesRead));//输出到工作台
17                //不断循环,直到读取完毕
18                if (bytesRead > 0)
19                    fs.BeginRead(data, 0, bufferSize, callback, null);//[3]
20                else
21                    fs.Close();//[4]
22            }
;
23
24            //异步读取文件
25            IAsyncResult async = fs.BeginRead(data, 0, bufferSize, callback, null);
26
27            Console.ReadLine();// 让黑屏等待,不会直接关闭..
28        }

29    }


对比
Code1.2代码我们可以看出匿名方法非常出色的完成我们功能在匿名方面体内 fs ([2][3][4])像普通变量一样执行引用FileStream([1]) 对象,而不需要任何的类型转换. 对象在方法之间轻松实现传递,并且从一个线程轻松迁移到另一个线程APM 编程而言这是十分完美的,但实际上编译器会重新编写您的代码,从堆栈中取出这些变量,并将它们作为字段嵌入对象。由于编译器会自动执行所有的工作,您可以很轻松地将最后一个参数的空值传递到BeginRead 方法,因为现在没有必要再在方法和线程之间显式传递的数据了。

注意1: 必须先AsyncCallback callback = null; 要不编程器会告诉你错误:” Use of unassigned local variable 'callback '”.

2,Lambda 表达式

我们只需要简单的修改(在执行同一操作,lambda 表达式语法比 C# 匿名方法更简洁),匿名方法,Code1.3中红色部分
callback = delegate(IAsyncResult asyncResult)

修改成

callback = asyncResult =>

下面是完整代码.

Code1.4

Code

 

最后,我们来看看异步的写操作(BeginWrite/EndWrite)

Code2

 1static class Program
 2    {
 3        static void Main()
 4        {
 5            FileStream fs = new FileStream("text.txt", FileMode.Create,
 6FileAccess.ReadWrite, FileShare.None, 20480true);//设置异步调用true
 7            //输入信息
 8            Console.Write("Please Enter:");
 9            byte[] data = Encoding.ASCII.GetBytes(Console.ReadLine());
10
11            //异步写文件
12            IAsyncResult async = fs.BeginWrite(data, 0, data.Length, asyncResult =>
13            {
14                fs.EndWrite(asyncResult);//写文件介绍,输出到text.txt文件中.
15                fs.Close();
16
17            }
null);
18
19            Console.ReadLine();// 让黑屏等待,不会直接关闭..
20        }

21    }


大家觉得是否很简单呢? 基本上所有具有异步行为的流(继承于System.IO.Stream)操作都可以按照类似于上面的代码编写. 当然其他异步行为也可以使用上面代码中的技巧. 在System.IO.Stream 中,提供了ReadTimeout/WriteTimeout 的超时处理,但是基类中是不支持的.会报 InvalidOperationException 异常,反编译可以看到throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported")).

相关文章推荐

C#异步操作文件流

在BahamutCMS中的页面生成依靠一个外部程序PGenerator.exe来读取mssql数据库中的发布命令,再生成页面。在这个io操作过程中,先是读取页面模版,将模版调用的文件(图片、js文件、...
  • foart
  • foart
  • 2011年11月10日 10:46
  • 2668

C#流Stream的使用总结

文件流占用资源比较多,而且工作效率叫低,所以在使用完流操作后应及时使用Close()关闭流 也可以使用using来及时的释放流所占用的资源 一、文件流FileStream  ...

【C#】62. 异步读写文件的几种方法: Task.Factory.FromAsync,WriteAsync

一、这里主要说明2种异步写入文件的方法: 1)异步编程模型API转为Task——使用Task.Factory.FromAsync方法 2)对于StreamWriter使用WriteAsync方法 请记...

C# FileStream流文件读写

//C#文件流写文件,默认追加FileMode.Append              string msg = "okffffffffffffffff";             byte[] ...

关于Stream的读写

public abstract int Read(byte[] buffer, int offset, int count) buffer: 字节数组。此方法返回时,该缓冲区包含指定的字符数组,该数...

黑马程序员之C#学习笔记:使用Stream.BeginRead方法读取FileStream的流内容

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

[VB.NET]TCP/IP协议进行通讯问题

 

mysql数据库的timeout设置

这几天上线了一个小网站,基本上是晚上测试没问题然后挂到网上。可是第二天就无法正常登录,并报出大量异常。 重启服务器后又可以正常运行,但是第二天问题依旧。 type Exception re...

.Net的异步机制(委托Delegate) - step 1

在阅读下面知识前,我已经认为你已经具有c#的基础,包括简单的委托知识; 代码使用VS2008开发,但是会在.Net Framework 2.0(C Sharp)编写   什么是.Net...
  • Ts_Coo
  • Ts_Coo
  • 2012年08月11日 21:11
  • 726

.Net的异步机制(Invoke,BeginInvoke,EndInvoke) - step 2

上一篇文章(什么是.Net的异步机制(委托Delegate) - step 1)中,我已经解释了什么是异步编程,那么现在我们就开始具体的说怎样异步编程.   我们怎样进行异步编程/开发...
  • Ts_Coo
  • Ts_Coo
  • 2012年08月11日 21:13
  • 559
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:.Net的异步机制(异步Stream读/写) - step 4
举报原因:
原因补充:

(最多只允许输入30个字)