您可以使用 Async 功能來存取檔案。 藉由使用異步功能,您可以呼叫異步方法,而不需使用回呼,或將程式代碼分割成多個方法或 Lambda 運算式。 若要將同步程式碼轉為異步程式碼,您只需呼叫異步方法而不是同步方法,並在程式碼中加入一些關鍵字。
您可能會考慮在檔案存取呼叫中加入異步處理的下列原因:
Asynchrony 讓 UI 應用程式更具回應性,因為啟動作業的 UI 線程可以執行其他工作。 如果UI線程必須執行長時間的程式代碼(例如超過50毫秒),UI可能會凍結,直到I/O完成,且UI線程可以再次處理鍵盤和滑鼠輸入和其他事件。
Asynchrony 藉由減少線程的需求,改善 ASP.NET 和其他伺服器型應用程式的延展性。 如果應用程式使用每個回應的專用線程,而且同時處理一千個要求,則需要一千個線程。 異步操作通常在等待期間不需要使用線程。 它們會在結尾短暫地使用現有的 I/O 完成線程。
在目前條件下,檔案存取作業的延遲可能非常低,但未來延遲可能會大幅增加。 例如,檔案可能會移至世界各地的伺服器。
使用異步功能的額外負荷很小。
異步工作可以輕鬆地平行執行。
執行範例
若要執行本主題中的範例,您可以建立 WPF 應用程式 或 Windows Forms 應用程式 ,然後新增 Button。 在按鈕的Click事件中,新增呼叫至每個範例中的第一個方法。
在下列範例中,包含下列 Imports 語句。
Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks
使用 FileStream 類別
本主題中的範例使用 FileStream 類別,其選項可啟用異步 I/O 在作業系統層級進行。 使用此選項,在許多情況下,您可以避免封鎖 ThreadPool 線程。 若要啟用此選項,您可以在建構函式呼叫中指定 useAsync=true 或 options=FileOptions.Asynchronous 自變數。
您無法使用此選項來搭配 StreamReader 和 StreamWriter,如果您直接藉由指定檔案路徑來開啟它們。 不過,如果您提供由 Stream 類別開啟的 FileStream,則可以使用此選項。 請注意,即使線程集區線程遭到封鎖,在 UI 應用程式中的異步呼叫速度也比較快,因為在等候期間不會封鎖 UI 線程。
撰寫文字
下列範例會將文字寫入檔案。 在每個 await 語句中,方法會立即退出。 當檔案 I/O 完成時,方法會在 await 語句之後的 語句繼續。 請注意,異步修飾詞位於使用 await 語句的方法定義中。
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
原始範例具有 語句 Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length),這是下列兩個 語句的收縮:
Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
Await theTask
第一個語句會傳回工作,並導致檔案處理開始。 第二個包含 await 的語句會導致該方法立即退出並返回另一個任務。 當檔案處理稍後完成時,執行會傳回 await 之後的 語句。 如需詳細資訊,請參閱異步程式中的控制流程(Visual Basic)。
閱讀文字
下列範例會從檔案讀取文字。 文字會緩衝處理,在此案例中,會放入 StringBuilder。 不同於上一個範例,await 的運算結果會產生一個值。
ReadAsync方法會傳回Task<Int32>,因此 await 的評估會在作業完成之後產生Int32值(numRead值)。 如需詳細資訊,請參閱 異步傳回型別 (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
平行異步輸入/輸出
下列範例示範藉由撰寫 10 個文字文件來進行平行處理。 針對每個檔案, WriteAsync 方法會傳回工作,然後新增至工作清單。
Await Task.WhenAll(tasks) 語句會結束方法,並在所有任務完成其檔案處理後在方法內繼續執行。
此範例會在工作完成之後關閉區塊中的所有FileStreamFinally實例。 如果每個 FileStream 而不是在 Imports 語句中建立,FileStream 可能會在工作完成前被處置。
請注意,任何效能提升幾乎完全來自平行處理,而不是異步處理。 異步的優點是它不會系結多個線程,而且不會系結使用者介面線程。
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
使用 WriteAsync 和 ReadAsync 方法時,您可以指定 CancellationToken,用於在操作過程中取消該操作。 如需詳細資訊,請參閱Fine-Tuning 您的非同步應用程式 (Visual Basic)和受控執行緒中的取消。