テキストファイルの内容を非同期的に読み込むには?[C#/VB、.NET 4.5]:.NET TIPS
.NET Framework 4.5以降で追加された「テキストファイルの内容を非同期で読み込むためのメソッド」の利用法を説明する。
テキストファイルを読み込むとき、そのファイルサイズが大きくて読み込みに時間がかかるようだと、その完了を待っている間はUIが無応答になってしまう。それを回避するにはファイル読み込みを非同期処理にすればよいのだが、これまではちょっと面倒だった。本稿では、.NET Framework 4.5で導入された簡単な方法を紹介する。
特定のトピックをすぐに知りたいという方は以下のリンクを活用してほしい。
関連TIPS
テキストファイルの内容を読み込むには、その目的や利用している.NET Frameworkのバージョンによって、さまざまな方法がある。適切な方法を選んでほしい。
- テキスト・ファイルの内容を読み込むには?[C#、VB]
- テキスト・ファイルの内容を簡単に読み込むには?[2.0のみ、C#、VB]
- テキスト・ファイルの内容を簡単かつ効率的に読み込むには?[4以降、C#、VB]
- テキストファイルの内容を非同期的に読み込むには?[C#/VB、.NET 4.5](本稿)
なお、本稿に掲載したサンプルコードをそのまま試すにはVisual Studio 2015以降が必要である。サンプルコードはコンソールアプリの一部であり、コードの冒頭に以下の宣言が必要となる。また、サンプルということで、例外処理は省略している。実際には、ファイルが存在していなかったり、アクセス権がなくて開けなかったりしたときなどに例外が発生するので、適切にtry〜catchしていただきたい。
using static System.Console;
Imports System.Console
ReadLineAsync:1行ずつ読み込む
テキストファイルを非同期的に読み込むには、StreamReaderクラス(System.IO名前空間)が使える。1行ずつ非同期的に読み込むなら、そのReadLineAsyncメソッドを使う(次のコード)。
StreamReaderオブジェクトを得る方法には幾つかあるが、ここではFileクラス(System.IO名前空間)のOpenTextメソッドを使った。また、文字エンコーディングを指定していないので、読み込むテキストファイルはUTF-8で書かれていなければならない。
static async void ReadLineAsync()
{
// 読み取るテキストファイル(実行ファイルと同じフォルダに置く)
const string TextFile = @".\sample_utf8.txt";
// テキストファイルのStreamReaderオブジェクトを得る
using (System.IO.StreamReader reader = System.IO.File.OpenText(TextFile))
{
string line;
int count = 1;
// ReadLineAsyncメソッドで非同期的に1行ずつ読み込み、変数lineに格納する
while ((line = await reader.ReadLineAsync()) != null)
WriteLine($"{count++}行目:{line}"); // 読み込んだ内容をコンソールに出力する
}
}
Async Sub ReadLineAsync()
' 読み取るテキストファイル(実行ファイルと同じフォルダに置く)
Const TextFile As String = ".\sample_utf8.txt"
' テキストファイルのStreamReaderオブジェクトを得る
Using reader As System.IO.StreamReader = System.IO.File.OpenText(TextFile)
Dim count As Integer = 1
While (True)
' ReadLineAsyncメソッドで非同期的に1行ずつ読み込み、変数lineに格納する
Dim line As String = Await reader.ReadLineAsync()
If (line Is Nothing) Then
Exit While
End If
WriteLine($"{count}行目:{line}") ' 読み込んだ内容をコンソールに出力する
count += 1
End While
End Using
End Sub
非同期メソッドを呼び出してその完了を待機するには、呼び出す部分にawaitキーワードが、また、メソッドのシグネチャにasyncキーワードが必要だ。また、StreamReaderクラスはIDisposableインタフェースを実装しているので、このコードのようにusing句を使って、間違いなくリソースが解放されるようにする。
なお、このメソッドを呼び出す側で、このメソッドの完了を待機したい場合は、このメソッドの返値をTask型(System.Threading.Tasks名前空間)に変える(メソッド本体のコードは変わらず)。
上のメソッドをコンソールアプリのMainメソッド内から呼び出してみると、次のコードのようになる。
ReadLineAsync();
WriteLine("ReadLineAsyncメソッドの呼び出し完了");
// 出力例:
// ReadLineAsyncメソッドの呼び出し完了
// 1行目:業務アプリInsider
// 2行目:テキストファイルの内容を非同期的に読み込むには?
ReadLineAsync()
WriteLine("ReadLineAsyncメソッドの呼び出し完了")
' 出力例:
' ReadLineAsyncメソッドの呼び出し完了
' 1行目:業務アプリInsider
' 2行目:テキストファイルの内容を非同期的に読み込むには?
出力例を見ると、ファイルの読み込み処理が終わる前に「呼び出し完了」のメッセージが出力されている。ファイルの読み込み処理が非同期的に実行されているためだ。ファイルの読み込みは非同期に実行されるが、場合によっては、読み込みが先に完了して上の出力例とは異なる順番で表示されることもある(以下同様)。
ReadToEndAsync:まとめて読み込む
テキストファイルを非同期的に読み込むには、StreamReaderクラス(System.IO名前空間)が使える。ファイルの全体をまとめて一気に読み込むなら、そのReadToEndAsyncメソッドを使う(次のコード)。
StreamReaderオブジェクトを得る方法には幾つかあるが、ここではStreamReaderクラスのコンストラクタを使った。また、文字エンコーディングを指定していないので、読み込むテキストファイルはUTF-8で書かれていなければならない。
static async void ReadToEndAsync()
{
// 読み取るテキストファイル(実行ファイルと同じフォルダに置く)
const string TextFile = @".\sample_utf8.txt";
// テキストファイルのStreamReaderオブジェクトを得る
using (var reader = new System.IO.StreamReader(TextFile))
{
// ReadToEndAsyncメソッドで非同期的にファイル全体を読み込み、変数に格納する
string allLines = await reader.ReadToEndAsync();
WriteLine($"UTF8ファイルの内容:「{allLines}」"); // 読み込んだ内容を出力する
}
}
Async Sub ReadToEndAsync()
' 読み取るテキストファイル(実行ファイルと同じフォルダに置く)
Const TextFile As String = ".\sample_utf8.txt"
' テキストファイルのStreamReaderオブジェクトを得る
Using reader = New System.IO.StreamReader(TextFile)
' ReadToEndAsyncメソッドで非同期的にファイル全体を読み込み、変数に格納する
Dim allLines As String = Await reader.ReadToEndAsync()
WriteLine($"UTF8ファイルの内容:「{allLines}」") ' 読み込んだ内容を出力する
End Using
End Sub
非同期メソッドを呼び出してその完了を待機するには、呼び出す部分にawaitキーワードが、また、メソッドのシグネチャにasyncキーワードが必要だ。また、StreamReaderクラスはIDisposableインタフェースを実装しているので、このコードのようにusing句を使って、間違いなくリソースが解放されるようにする。
なお、このメソッドを呼び出す側で、このメソッドの完了を待機したい場合は、このメソッドの返値をTask型(System.Threading.Tasks名前空間)に変える(メソッド本体のコードは変わらず)。
上のメソッドをコンソールアプリのMainメソッド内から呼び出してみると、次のコードのようになる。
ReadToEndAsync();
WriteLine("ReadToEndAsyncメソッドの呼び出し完了");
// 出力例:
// ReadToEndAsyncメソッドの呼び出し完了
// UTF8ファイルの内容:「業務アプリInsider
// テキストファイルの内容を非同期的に読み込むには?」
ReadToEndAsync()
WriteLine("ReadToEndAsyncメソッドの呼び出し完了")
' 出力例:
' ReadToEndAsyncメソッドの呼び出し完了
' UTF8ファイルの内容:「業務アプリInsider
' テキストファイルの内容を非同期的に読み込むには?」
出力例を見ると、ファイルの読み込み処理が終わる前に「呼び出し完了」のメッセージが出力されている。ファイルの読み込み処理が非同期的に実行されているためだ。
文字エンコーディングを指定するには?
読み込むテキストファイルの文字エンコーディングがUTF-8以外の場合は、StreamReaderクラス(System.IO名前空間)のインスタンスを作るときにエンコーディングを指定する。その後の読み込む処理は、ここまでに述べてきた方法と同じである。例えば、シフトJISのテキストファイルの全体を非同期的に一気に読み込むメソッドは、次のコードのようになる。
GetEncodingメソッドに指定できる文字列については、Encodingクラス(System.Text名前空間)のドキュメントを参照してほしい。
static async void ReadSjisAsync()
{
// 読み取るテキストファイル(実行ファイルと同じフォルダに置く)
const string TextFile = @".\sample_sjis.txt";
// シフトJISの文字エンコーディングオブジェクトを用意する
var sjis = System.Text.Encoding.GetEncoding("shift_jis");
// StreamReaderオブジェクトを作るときにエンコーディングを指定する
using (var reader = new System.IO.StreamReader(TextFile, sjis))
{
string allLines = await reader.ReadToEndAsync();
WriteLine($"シフトJISファイルの内容:「{allLines}」");
}
}
Async Sub ReadSjisAsync()
' 読み取るテキストファイル(実行ファイルと同じフォルダに置く)
Const TextFile As String = ".\sample_sjis.txt"
' シフトJISの文字エンコーディングオブジェクトを用意する
Dim sjis = System.Text.Encoding.GetEncoding("shift_jis")
' StreamReaderオブジェクトを作るときにエンコーディングを指定する
Using reader = New System.IO.StreamReader(TextFile, sjis)
Dim allLines As String = Await reader.ReadToEndAsync()
WriteLine($"シフトJISファイルの内容:「{allLines}」")
End Using
End Sub
非同期メソッドを呼び出してその完了を待機するには、呼び出す部分にawaitキーワードが、また、メソッドのシグネチャにasyncキーワードが必要だ。また、StreamReaderクラスはIDisposableインタフェースを実装しているので、このコードのようにusing句を使って、間違いなくリソースが解放されるようにする。
なお、このメソッドを呼び出す側で、このメソッドの完了を待機したい場合は、このメソッドの返値をTask型(System.Threading.Tasks名前空間)に変える(メソッド本体のコードは変わらず)。
上のメソッドをコンソールアプリのMainメソッド内から呼び出してみると、次のコードのようになる。
ReadSjisAsync();
WriteLine("ReadSjisAsyncメソッドの呼び出し完了");
// 出力例:
// ReadSjisAsyncメソッドの呼び出し完了
// シフトJISファイルの内容:「業務アプリInsider
// テキストファイルの内容を非同期的に読み込むには?」
ReadSjisAsync()
WriteLine("ReadSjisAsyncメソッドの呼び出し完了")
' 出力例:
' ReadSjisAsyncメソッドの呼び出し完了
' シフトJISファイルの内容:「業務アプリInsider
' テキストファイルの内容を非同期的に読み込むには?」
出力例を見ると、ファイルの読み込み処理が終わる前に「呼び出し完了」のメッセージが出力されている。ファイルの読み込み処理が非同期的に実行されているためだ。
まとめ
テキストファイルを非同期的に読み込むには、StreamReaderクラスを使う。1行ずつ非同期的に読み込むならReadLineAsyncメソッドを、ファイルの全体をまとめて一気に読み込むならReadToEndAsyncメソッドを利用する。また、文字エンコーディングは、StreamReaderクラスのコンストラクタで指定する。
なお、すでに開かれているファイルを読み込むときには、FileStreamクラスを併用する。詳細は「オープン中のファイルにアクセスするには?[C#、VB]」をご覧いただきたい。
利用可能バージョン:.NET Framework 4.5以降
カテゴリ:クラスライブラリ 処理対象:テキストファイル
使用ライブラリ:Fileクラス(System.IO名前空間
使用ライブラリ:StreamReaderクラス(System.IO名前空間)
使用ライブラリ:Encodingクラス(System.Text名前空間)
関連TIPS:テキスト・ファイルの内容を読み込むには?[C#、VB]
関連TIPS:テキスト・ファイルの内容を簡単に読み込むには?[2.0のみ、C#、VB]
関連TIPS:テキスト・ファイルの内容を簡単かつ効率的に読み込むには?[4以降、C#、VB]
関連TIPS:async/awaitで例外処理をするには?[C#/VB]
関連TIPS:オープン中のファイルにアクセスするには?[C#、VB]
関連TIPS:ファイルをコピー/削除/リネーム/移動するには?
関連TIPS:ファイルにテキストを書き込むには?[C#、VB]
関連TIPS:バイナリ・ファイルを読み書きするには?
関連TIPS:構文:クラス名を書かずに静的メソッドを呼び出すには?[C# 6.0]
関連TIPS:VB.NETでクラス名を省略してメソッドや定数を利用するには?
関連TIPS:数値を右詰めや0埋めで文字列化するには?[C#、VB]
Copyright© Digital Advantage Corp. All Rights Reserved.