ファイル アクセスにおける非同期の使用 (C# および Visual Basic)

ファイルにアクセスするために [Async] の機能を使用できます。非同期機能を使用して、非同期メソッドにコールバックを使用せずに呼び出すことができますが、または複数のメソッドまたはラムダ式の間でのコードを切り離して。同期コードを非同期にするには、同期メソッドの代わりに、非同期メソッドを呼び出し、コードにいくつかのキーワードが追加されます。

ファイル アクセスの呼び出しを追加するには、次の理由を asynchrony 検討する可能性があります:

  • Asynchrony は、操作の開始 UI スレッドが他の処理を実行できるため、UI のアプリケーションの応答性になります。UI スレッドに時間 (ミリ秒) または 50 を受け取るコードを実行する必要がある場合は、UI は、I/O が完全になり、UI スレッドが再びキーボードとマウス入力やそのほかのイベントを処理するまで固定場合があります。

  • Asynchrony は、スレッドの必要性が軽減され、ASP.NET のスケーラビリティ、および他のサーバー ベースのアプリケーションをアップグレードします。アプリケーションが応答ごとの専用スレッドを使用し、千の要求が処理されると同時に、千のスレッドが必要です。非同期操作は、待機中のスレッドを使用する必要はありません。これらは末尾で既存の I/O 完了スレッドを簡単に使用します。

  • ファイル アクセス操作の待機時間が非常に小さい下の現在の状態である場合は、待機時間が非常ともに増加する可能性があります。たとえば、ファイルは世界であるサーバーに移動する場合があります。

  • 単一の機能の使用に関するオーバーヘッドが小さくなります。

  • 非同期タスクを簡単に並列に実行します。

例の実行

[!メモ]

このトピックの例では、Windows ストア にタッチ対話に全画面表示 Windows 8、同期の apps である apps を追加されません。Windows ストア の apps で async ファイルにアクセスする方法については、Windows ストア アプリ用 .NET の概要ファイルおよびストリーム入出力を参照してください。Windows ストア の apps のファイル I/O 例については、ダウンロード アクセスのサンプルをファイル。できます。

このトピックの例を実行するには、[WPF アプリケーション][Windows フォーム アプリケーション] を作成し、**[ボタン]**を追加できます。ボタンの Click のイベントでは、各例の最初のメソッドの呼び出しを追加します。

次の例では、次の Imports (Visual Basic) または (C#) ステートメント using を含めます。

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 のクラスの使用

このトピックの例では、非同期 I/O がオペレーティング システムのレベルに対して選択できる FileStream のクラスを使用します。このオプションを使用すると、ThreadPool のスレッドを多くの場合、ブロック回避できます。このオプションを有効にするには、コンストラクターの呼び出しで useAsync=true または options=FileOptions.Asynchronous 引数を指定します。

直接ファイルのパスを指定してそれらを開くと StreamReaderStreamWriter のこのオプションは使用できません。ただし、FileStream のクラスが開いた Stream を指定すると、このオプションを使用できます。UI スレッドに待機中にブロックするため ThreadPool のスレッドがブロックは非同期呼び出しが UI apps により速いことに注意してください。

テキストを記述できます。

次の例では、ファイルの書き込みに表示します。各ステートメントで、メソッドをすぐに終了するまで待ちます。ファイル I/O が完了すると、メソッドは予定のステートメントの次のステートメントから再開します。async 修飾子が期待のステートメントを使用するメソッドの定義であることに注意してください。

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);
    };
}

元の例では、次の 2 種類のステートメントのシュリンクラッピングであるステートメント 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;

最初のステートメントでは、タスクを返し、原因を開始するファイルを処理します。要求の 2 番目のステートメントでは、メソッドはすぐに別のタスクを終了して返します。後で処理するファイルが完了すると、実行が期待に続くステートメントに制御が返されます。詳細については、「非同期プログラムにおける制御フロー (C# および Visual Basic)」および「チュートリアル: 非同期メソッドと共にデバッガーを使用する」を参照してください。

テキストを読み取ること

ファイルからテキストを読み取る例を次に示します。テキスト バッファーは StringBuilderに、この場合、設定されます。前の例のとは異なり、それらの評価は値を生成します。ReadAsync のメソッドは Task<Int32> を返すため、操作の完了後、の評価は Int32 の値 (numRead) を生成します。詳細については、「非同期の戻り値の型 (C# および 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 は、タスクが完了する前にに破棄されることがあります。

どのパフォーマンス Boost が処理し、非同期処理する並列からほとんど完全にないことに注意してください。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)」および「マネージ スレッドのキャンセル」を参照してください。

参照

処理手順

チュートリアル: 非同期メソッドと共にデバッガーを使用する

概念

Async および Await を使用した非同期プログラミング (C# および Visual Basic)

非同期の戻り値の型 (C# および Visual Basic)

非同期プログラムにおける制御フロー (C# および Visual Basic)