异步文件 I/OAsynchronous File I/O

异步操作使您能在不阻塞主线程的情况下执行占用大量资源的 I/O 操作。Asynchronous operations enable you to perform resource-intensive I/O operations without blocking the main thread. 在 Windows 8.x 应用商店应用或桌面应用中一个耗时的流操作可能阻塞 UI 线程并让应用看起来好像不工作时,这种性能的考虑就显得尤为重要了。This performance consideration is particularly important in a Windows 8.x Store app or desktop app where a time-consuming stream operation can block the UI thread and make your app appear as if it is not working.

从 .NET Framework 4.5 开始,I/O 类型包括异步方法来简化异步操作。Starting with the .NET Framework 4.5, the I/O types include async methods to simplify asynchronous operations. 异步方法在其名称中包括 Async ,例如 ReadAsyncWriteAsyncCopyToAsyncFlushAsyncReadLineAsyncReadToEndAsyncAn async method contains Async in its name, such as ReadAsync, WriteAsync, CopyToAsync, FlushAsync, ReadLineAsync, and ReadToEndAsync. 这些异步方法基于流类(例如 StreamFileStreamMemoryStream)和用来向流中读出或写入数据的类(例如 TextReaderTextWriter)实现。These async methods are implemented on stream classes, such as Stream, FileStream, and MemoryStream, and on classes that are used for reading from or writing to streams, such TextReader and TextWriter.

在 .NET Framework 4 和更早的版本中,您必须使用 BeginReadEndRead 之类的方法来实现异步 I/O 操作。In the .NET Framework 4 and earlier versions, you have to use methods such as BeginRead and EndRead to implement asynchronous I/O operations. 这些方法仍然在 .NET Framework 4.5 中可用,从而支持传统的代码;但是,异步方法能帮助你更轻松地实现异步 I/O 操作。These methods are still available in the .NET Framework 4.5 to support legacy code; however, the async methods help you implement asynchronous I/O operations more easily.

C# 和 Visual Basic 分别具有两个用于异步编程的关键字:C# and Visual Basic each have two keywords for asynchronous programming:

  • Async (Visual Basic) 或 async (C#) 修饰符,您可以用来标记包含异步操作的方法。Async (Visual Basic) or async (C#) modifier, which is used to mark a method that contains an asynchronous operation.

  • Await (Visual Basic) 或 await (C#) 运算符,可以应用到异步方法的结果中。Await (Visual Basic) or await (C#) operator, which is applied to the result of an async method.

如下面的示例所示,若要实现异步 I/O 操作,请把这些关键字和异步方法结合使用。To implement asynchronous I/O operations, use these keywords in conjunction with the async methods, as shown in the following examples. 有关详细信息,请参阅使用 async 和 await 的异步编程 (C#)使用 Async 和 Await 的异步编程 (Visual Basic)For more information, see Asynchronous programming with async and await (C#) or Asynchronous Programming with Async and Await (Visual Basic).

下面的示例演示如何使用两个 FileStream 对象把文件从一个目录异步复制到另一个目录。The following example demonstrates how to use two FileStream objects to copy files asynchronously from one directory to another. 需要注意 Click 控件的 Button 事件处理程序具有 async 修饰符标记,因为它调用异步方法。Notice that the Click event handler for the Button control is marked with the async modifier because it calls an asynchronous method.

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);
                    }
                }
            }
        }
    }
}
Imports System.IO

Class MainWindow

    Private Async Sub Button_Click(sender As Object, e As RoutedEventArgs)
        Dim StartDirectory As String = "c:\Users\exampleuser\start"
        Dim EndDirectory As String = "c:\Users\exampleuser\end"

        For Each filename As String In Directory.EnumerateFiles(StartDirectory)
            Using SourceStream As FileStream = File.Open(filename, FileMode.Open)
                Using DestinationStream As FileStream = File.Create(EndDirectory + filename.Substring(filename.LastIndexOf("\"c)))
                    Await SourceStream.CopyToAsync(DestinationStream)
                End Using

            End Using
        Next
    End Sub

End Class

下一个例子类似于前面的例子,但是使用 StreamReaderStreamWriter 对象以异步方式读取和写入文本文件的内容。The next example is similar to the previous one but uses StreamReader and StreamWriter objects to read and write the contents of a text file asynchronously.

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);
    } 
} 
Private Async Sub Button_Click(sender As Object, e As RoutedEventArgs)
    Dim UserDirectory As String = "c:\Users\exampleuser\"

    Using SourceReader As StreamReader = File.OpenText(UserDirectory + "BigFile.txt")
        Using DestinationWriter As StreamWriter = File.CreateText(UserDirectory + "CopiedFile.txt")
            Await CopyFilesAsync(SourceReader, DestinationWriter)
        End Using
    End Using
End Sub

Public Async Function CopyFilesAsync(Source As StreamReader, Destination As StreamWriter) As Task
    Dim buffer(4095) As Char
    Dim numRead As Integer

    numRead = Await Source.ReadAsync(buffer, 0, buffer.Length)
    Do While numRead <> 0
        Await Destination.WriteAsync(buffer, 0, numRead)
        numRead = Await Source.ReadAsync(buffer, 0, buffer.Length)
    Loop
    
End Function

下一个示例演示用于在 Windows 8.x 应用商店应用中以 Stream 的形式打开文件的代码隐藏文件和 XAML 文件,并且通过使用 StreamReader 类的实例来读取其内容。The next example shows the code-behind file and the XAML file that are used to open a file as a Stream in a Windows 8.x Store app, and read its contents by using an instance of the StreamReader class. 它使用异步方法以流的形式打开文件并读取其内容。It uses asynchronous methods to open the file as a stream and to read its contents.

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
{
    public sealed partial class BlankPage : Page
    {
        public BlankPage()
        {
            this.InitializeComponent();
        }

        private async void 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();
        }
    }
}
Imports System.Text
Imports System.IO
Imports Windows.Storage.Pickers
Imports Windows.Storage

NotInheritable Public Class BlankPage
    Inherits Page

    

    Private Async Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
        Dim contents As StringBuilder = New StringBuilder()
        Dim nextLine As String
        Dim lineCounter As Integer = 1

        Dim openPicker = New FileOpenPicker()
        openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary

        openPicker.FileTypeFilter.Add(".txt")
        Dim selectedFile As StorageFile = Await openPicker.PickSingleFileAsync()

        Using reader As StreamReader = New StreamReader(Await selectedFile.OpenStreamForReadAsync())
            nextLine = Await reader.ReadLineAsync()
            While (nextLine <> Nothing)
                contents.AppendFormat("{0}. ", lineCounter)
                contents.Append(nextLine)
                contents.AppendLine()
                lineCounter = lineCounter + 1
                If (lineCounter > 3) Then
                    contents.AppendLine("Only first 3 lines shown.")
                    Exit While
                End If
                nextLine = Await reader.ReadLineAsync()
            End While
        End Using
        DisplayContentsBlock.Text = contents.ToString()
    End Sub
End Class
<Page
    x:Class="ExampleApplication.BlankPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ExampleApplication"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackPanel Background="{StaticResource ApplicationPageBackgroundBrush}" VerticalAlignment="Center" HorizontalAlignment="Center">
        <TextBlock Text="Display lines from a file."></TextBlock>
        <Button Content="Load File" Click="Button_Click_1"></Button>
        <TextBlock Name="DisplayContentsBlock"></TextBlock>
    </StackPanel>
</Page>

请参阅See also