.NET4.5新功能:异步文件I/O
异步操作可以执行大量占用资源的 I/O 操作,而不必阻止主线程。 此性能注意事项非常重要。 windows Metro style app 或 desktop app 耗时的流操作会阻止 UI 线程并将您的应用程序显示的位置,就象它不起作用。
从开始 .NET Framework 4.5 RC, I/O 类型包括异步方法简化异步操作。 异步方法在其名称中包含 Async ,例如 ReadAsync、 WriteAsync、 CopyToAsync、 FlushAsync、 ReadLineAsync和 ReadToEndAsync。 这些异步方法对流类,如 Stream、 FileStream和 MemoryStream以及用于读取或写入使用至流 (如 TextReader 和 TextWriter的类。
在 .NET framework 4 和早期版本中,必须使用之类的方法 BeginRead 和 EndRead 实现异步 I/O 操作。 这些方法可在 .NET Framework 4.5 RC 支持旧版代码;但是,异步方法帮助您更轻松地实现异步 I/O 操作。
从开始 Visual Studio 2012 RC, Visual Studio 为异步编程提供两个关键字:
• Async (Visual Basic) 或 (c#) async 修饰符,用于指示方案包含一个异步操作。
• Await (Visual Basic) 或 (c#) await 运算符,会应用于异步方法的结果。
如下面的示例所示,若要实现异步 I/O 操作,请使用异步方法结合使用这些关键字,。 有关更多信息,请参见 异步编程与异步和等待 (C# 和 Visual Basic)。
下面的示例演示如何使用复制文件的两 FileStream 对象异步从一个目录到另一个。 请注意 Button 控件的 Click 事件处理程序标记 async 修饰符,因为它调用异步方法。
using System;
using System.Threading.Tasks;
using System.Windows;
using System.IO;
namespace WpfApplication
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
string StartDirectory = @"c:\Users\exampleuser\start";
string EndDirectory = @"c:\Users\exampleuser\end";
foreach (string filename in Directory.EnumerateFiles(StartDirectory))
{
using (FileStream SourceStream = File.Open(filename, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(EndDirectory + filename.Substring(filename.LastIndexOf('\\'))))
{
await SourceStream.CopyToAsync(DestinationStream);
}
}
}
}
}
}
下一个示例与前一个示例相似,但使用 StreamReader 和 StreamWriter 对象读取和写入文本文件的内容异步。
private async void Button_Click(object sender, RoutedEventArgs e)
{
string UserDirectory = @"c:\Users\exampleuser\";
using (StreamReader SourceReader = File.OpenText(UserDirectory + "BigFile.txt"))
{
using (StreamWriter DestinationWriter = File.CreateText(UserDirectory + "CopiedFile.txt"))
{
await CopyFilesAsync(SourceReader, DestinationWriter);
}
}
}
public async Task CopyFilesAsync(StreamReader Source, StreamWriter Destination)
{
char[] buffer = new char[0x1000];
int numRead;
while ((numRead = await Source.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
await Destination.WriteAsync(buffer, 0, numRead);
}
}
使用 StreamReader 类的实例,下一个示例演示用于打开文件为 Metro style app 的 Stream 的代码隐藏文件和 XAML 文件之后和读取其内容。 它使用异步方法打开文件以流和读取其内容。
using System;
using System.IO;
using System.Text;
using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace ExampleApplication
{
publicsealedpartialclass BlankPage : Page
{
public BlankPage()
{
this.InitializeComponent();
}
privateasyncvoid Button_Click_1(object sender, RoutedEventArgs e)
{
StringBuilder contents = new StringBuilder();
string nextLine;
int lineCounter = 1;
var openPicker = new FileOpenPicker();
openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
openPicker.FileTypeFilter.Add(".txt");
StorageFile selectedFile = await openPicker.PickSingleFileAsync();
using (StreamReader reader = new StreamReader(await selectedFile.OpenStreamForReadAsync()))
{
while ((nextLine = await reader.ReadLineAsync()) != null)
{
contents.AppendFormat("{0}. ", lineCounter);
contents.Append(nextLine);
contents.AppendLine();
lineCounter++;
if (lineCounter > 3)
{
contents.AppendLine("Only first 3 lines shown.");
break;
}
}
}
DisplayContentsBlock.Text = contents.ToString();
}
}
}
摘自 love007