使用匿名方法进行异步文件 IO






2.89/5 (10投票s)
一篇关于如何使用匿名方法在 C# 中进行异步文件 IO 的文章。
引言
在本文中,我将解释如何使用匿名方法在 C# 中编写代码以实现异步文件 IO。
使用代码
本文中的示例代码可以用作模板;只需根据您的需求填写各个部分并使用它即可。
以下是代码的一些解释
我首先定义了一些变量
FileStream fs = new FileStream("C:\\sample.txt",FileMode.Open);
Byte[] data = new byte[200];
long timeNow = Stopwatch.GetTimestamp();
请注意,我使用了一种稍微隐晦的方式来读取文件。通常,您会使用 StreamReader
,因为它经过优化以读取文本。但是,StreamReader
不支持异步读取,因此我们必须使用 FileStream
来读取数据。使用 FileStream
,数据以 byte[] 的形式读取,并且可以轻松转换为 string
,如下所示
fs.BeginRead
(data,
0,
data.Length,
delegate(IAsyncResult ar) { /* Section 1...some code*/ },
null);
接下来,我们进行实际的异步读取。任何支持异步操作的类都会有类似 Beginxxx
和 Endxxx
的方法。
我已传递
byte[] data
-- 它将保存读取后的数据,- 0 -- 以表明读取应从文件的开头开始,
data.Length
-- 我要从文件中读取的字节数(请记住,如果文件是 Unicode 格式,则 1 个字符 == 2 个字节,将其转换为字符串也需要不同的编码。)
- 一个委托 -- 它将实际进行文件读取,最后
null
-- 因为我不想保存任何状态。为什么?我在正式定义之后解释过。
FileStream
中的 BeginRead
的正式定义为
public override System.IAsyncResult BeginRead(byte[] array, int offset, int numBytes,
System.AsyncCallback userCallback, object stateObject)
//Member of System.IO.FileStream
摘要
开始异步读取。
参数
offset
:开始读取的数组中的字节偏移量。array
:将数据读取到的缓冲区。numBytes
:要读取的最大字节数。userCallback
:异步读取操作完成后要调用的方法。stateObject
:用户提供的对象,用于将此特定的异步读取请求与其他请求区分开来。
Returns
一个 System.IAsyncResult
,它引用异步读取。
异常
System.ArgumentNullException
:array 为 null。System.ArgumentOutOfRangeException
:offset
或numBytes
为负数。System.ArgumentException
:数组长度减去偏移量小于numBytes
。System.IO.IOException
:尝试在文件末尾之后进行异步读取。
有两种方法可以进行此调用:一种是我编写的方式,另一种方式是显式编写一个将进行读取的函数,在这种情况下,我们必须将 FileStream
对象作为 stateObject
传递 - 最后一个参数。
我实现了一个匿名方法来摆脱额外的函数,这也摆脱了保存状态并将其传递给实际函数的所有麻烦。
// Section 1
// =========
int bytesRead = fs.EndRead(ar);
fs.Close();
Console.WriteLine(ASCIIEncoding.ASCII.GetString(data));
Console.WriteLine("Time stamp to end section 1 : {0}",
Stopwatch.GetTimestamp()-timeNow);
由于我们在同一个函数中,因此所有对象都已可访问。我们仅在 EndRead
方法中使用它。
之后,我使用 ASCIIEncoding
将 byte[] data
转换为 string
,最后,为了证明第 1 节和第 2 节是并行运行的,时间戳显示在控制台中。
// Section 2
// =========
Console.WriteLine("Time stamp to end section 2 : {0}",
Stopwatch.GetTimestamp()-timeNow);
Console.ReadLine();
最后,第 2 节紧跟在 BeginRead
调用之后。在这里,我们再次只写入秒表值并等待用户输入。请记住,我们有两个托管线程正在运行,因此如果我们在运行第 2 节之后关闭程序,我们可能没有足够的时间让第 1 节完成。
关注点
尽管代码非常简单,但它的正确用法却并非易事,您的项目必须进行架构设计,以便它可以利用异步编程的特性。
历史
- 提交此文章:2006 年 8 月 15 日。