共用方式為


使用非同步方式存取檔案 (C# 和 Visual Basic)

您可以使用 用於初始化 功能存取檔案。經由非同步功能,您可以呼叫非同步方法,而不需使用回呼或分割成跨多個方法或 Lambda 運算式的程式碼。若要讓同步程式碼,您非同步呼叫非同步方法而不是同步方法並加入一些關鍵字加入至程式碼。

您可能會認為下列原因而加入的 asynchrony 至檔案存取呼叫:

  • Asynchrony 呈現 UI 應用程式回應更快,因為啟動動作的 UI 執行緒可以同時執行其他工作。如果 UI 執行緒執行時間太長的程式碼 (例如,超過 50 毫秒), UI 可能凍結,直到 I/O 完成,且 UI 執行緒可以重新處理鍵盤和滑鼠輸入和其他事件。

  • Asynchrony 減少對執行緒的需求改善 ASP.NET 和其他的延展性伺服器架構的應用程式。如果應用程式使用專用執行緒每個回應,而且一次要求同時處理,千位執行緒所需的項目。在等待期間,非同步作業通常不需要使用執行緒。它們是簡單地使用現有的 I/O 完成執行緒會結束。

  • 檔案存取作業的延遲可能非常小底下當時狀況,不過,延遲時間可能會大幅增加。例如,檔案可能會移至位於世界的伺服器。

  • 要加入的額外負荷使用 Async 功能很小。

  • 非同步工作可以輕易平行執行。

執行範例

注意事項注意事項

本主題中的範例不適用於 Windows 市集 應用程式,這 Windows 8 應用程式是全螢幕模式和量身訂做以連續互動。如需如何使用非同步檔案存取的資訊。 Windows 市集 應用程式,請參閱 適用於 Windows 市集應用程式的 .NET 概觀檔案和資料流 I/O。以 Windows 市集 應用程式的檔案 I/O 的範例,請下載。 檔案存取範例

若要執行本主題中的範例,您可以建立 [WPF 應用程式] 或 [Windows Form 應用程式] 然後將 [按鈕]。在按鈕的 Click 事件,請將呼叫加入至每個範例中的第一個方法。

在下列範例中,加入下列 Imports (Visual Basic) 或 using (C#) 陳述式。

Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;

對 FileStream 類別的使用。

本主題中的範例使用 FileStream 類別,可以選擇讓非同步 I/O 發生在這個作業系統的層級。您可以使用這個選項,您就可以避免在許多情況下 ThreadPool 封鎖執行緒。若要啟用這個選項,您在建構函式呼叫指定 useAsync=true 或 options=FileOptions.Asynchronous 引數。

您不可以在 StreamReaderStreamWriter 的選項,如果您直接透過指定檔案路徑開啟這些檔案。不過,您可以使用這個選項時,如果提供它們 FileStream 類別開啟的 Stream 。請注意非同步呼叫速度在 UI 應用程式,即使 ThreadPool 執行緒被封鎖,在等待期間,,因為 UI 執行緒不會封鎖。

文字

下列範例會將文字寫入檔案。在每種都會等候陳述式,則方法將會立即結束。當檔案 I/O 完成時,方法會繼續在等候接在陳述式之後的陳述式。請注意非同步修飾詞在使用等待陳述式方法的定義。

Public Async Sub ProcessWrite()
    Dim filePath = "temp2.txt"
    Dim text = "Hello World" & ControlChars.CrLf

    Await WriteTextAsync(filePath, text)
End Sub

Private Async Function WriteTextAsync(filePath As String, text As String) As Task
    Dim encodedText As Byte() = Encoding.Unicode.GetBytes(text)

    Using sourceStream As New FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.None,
        bufferSize:=4096, useAsync:=True)

        Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
    End Using
End Function
public async void ProcessWrite()
{
    string filePath = @"temp2.txt";
    string text = "Hello World\r\n";

    await WriteTextAsync(filePath, text);
}

private async Task WriteTextAsync(string filePath, string text)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(text);

    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.None,
        bufferSize: 4096, useAsync: true))
    {
        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    };
}

原始的範例有陳述式 await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);,為下列兩個陳述式的縮小:

Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
Await theTask
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
await theTask;

第一個陳述式會傳回工作,而造成檔案啟動的處理序。使用等待的第二個陳述式會立即完成並傳回不同的工作。當稍後處理檔案完成時,執行溯回等候的陳述式。如需詳細資訊,請參閱非同步程式中的控制流程 (C# 和 Visual Basic)逐步解說:搭配非同步方法使用偵錯工具

讀取文字

下列範例會從檔案中讀取文字。文字緩衝區,並,在此情況下,會放入 StringBuilder。不同於上述範例,等候的評估產生值。ReadAsync 方法傳回 Task<Int32>,因此,等待的評估產生 Int32 值 (numRead),在作業完成之後。如需詳細資訊,請參閱非同步方法的傳回型別 (C# and Visual Basic)

Public Async Sub ProcessRead()
    Dim filePath = "temp2.txt"

    If File.Exists(filePath) = False Then
        Debug.WriteLine("file not found: " & filePath)
    Else
        Try
            Dim text As String = Await ReadTextAsync(filePath)
            Debug.WriteLine(text)
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try
    End If
End Sub

Private Async Function ReadTextAsync(filePath As String) As Task(Of String)

    Using sourceStream As New FileStream(filePath,
        FileMode.Open, FileAccess.Read, FileShare.Read,
        bufferSize:=4096, useAsync:=True)

        Dim sb As New StringBuilder

        Dim buffer As Byte() = New Byte(&H1000) {}
        Dim numRead As Integer
        numRead = Await sourceStream.ReadAsync(buffer, 0, buffer.Length)
        While numRead <> 0
            Dim text As String = Encoding.Unicode.GetString(buffer, 0, numRead)
            sb.Append(text)

            numRead = Await sourceStream.ReadAsync(buffer, 0, buffer.Length)
        End While

        Return sb.ToString
    End Using
End Function
public async void ProcessRead()
{
    string filePath = @"temp2.txt";

    if (File.Exists(filePath) == false)
    {
        Debug.WriteLine("file not found: " + filePath);
    }
    else
    {
        try
        {
            string text = await ReadTextAsync(filePath);
            Debug.WriteLine(text);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }
}

private async Task<string> ReadTextAsync(string filePath)
{
    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Open, FileAccess.Read, FileShare.Read,
        bufferSize: 4096, useAsync: true))
    {
        StringBuilder sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
}

平行非同步 I/O

下列範例會藉由將 10 文字檔示範平行處理。對於每一個檔案, WriteAsync 方法傳回可加入至工作清單中的工作。在檔案處理所有已完成工作時, await Task.WhenAll(tasks); 陳述式來結束方法並在方法中復原。

在工作完成後,範例會關閉。 finally 區塊中的任何 FileStream 執行個體。如果每個 FileStream 在 using 陳述式建立, FileStream 可能已處理,在工作完成之前。

請注意任何效能提升幾乎全部是從非同步處理平行處理而不是。asynchrony 的優點是它不會佔用多執行緒,因此,它不會佔用使用者介面執行緒。

Public Async Sub ProcessWriteMult()
    Dim folder = "tempfolder\"
    Dim tasks As New List(Of Task)
    Dim sourceStreams As New List(Of FileStream)

    Try
        For index = 1 To 10
            Dim text = "In file " & index.ToString & ControlChars.CrLf

            Dim fileName = "thefile" & index.ToString("00") & ".txt"
            Dim filePath = folder & fileName

            Dim encodedText As Byte() = Encoding.Unicode.GetBytes(text)

            Dim sourceStream As New FileStream(filePath,
                FileMode.Append, FileAccess.Write, FileShare.None,
                bufferSize:=4096, useAsync:=True)

            Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
            sourceStreams.Add(sourceStream)

            tasks.Add(theTask)
        Next

        Await Task.WhenAll(tasks)
    Finally
        For Each sourceStream As FileStream In sourceStreams
            sourceStream.Close()
        Next
    End Try
End Sub
public async void ProcessWriteMult()
{
    string folder = @"tempfolder\";
    List<Task> tasks = new List<Task>();
    List<FileStream> sourceStreams = new List<FileStream>();

    try
    {
        for (int index = 1; index <= 10; index++)
        {
            string text = "In file " + index.ToString() + "\r\n";

            string fileName = "thefile" + index.ToString("00") + ".txt";
            string filePath = folder + fileName;

            byte[] encodedText = Encoding.Unicode.GetBytes(text);

            FileStream sourceStream = new FileStream(filePath,
                FileMode.Append, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true);

            Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
            sourceStreams.Add(sourceStream);

            tasks.Add(theTask);
        }

        await Task.WhenAll(tasks);
    }

    finally
    {
        foreach (FileStream sourceStream in sourceStreams)
        {
            sourceStream.Close();
        }
    }
}

當使用 WriteAsyncReadAsync 方法時,您可以指定 CancellationToken,您可以使用取消作業中途。如需詳細資訊,請參閱微調非同步應用程式 (C# 和 Visual Basic)Managed 執行緒中的取消作業

請參閱

工作

逐步解說:搭配非同步方法使用偵錯工具

概念

使用 Async 和 Await 設計非同步程式 (C# 和 Visual Basic)

非同步方法的傳回型別 (C# and Visual Basic)

非同步程式中的控制流程 (C# 和 Visual Basic)