非同步檔案 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 Store 應用程式或傳統型應用程式而言特別重要,尤其是針對耗時的資料流作業可能會阻礙 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. 這些非同步方法會在 Stream 類別上實作 (例如 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

下一個範例顯示程式碼後置檔案和 XAML 檔案,可用來開啟檔案作為 Stream 應用程式中的 Windows 8.x Store ,並使用 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