C#でのファイル入出力は、.Net Frameworkのストリームを使用します。ストリームは、C#のI/O(Input/Output:入出力)の基盤です。
.Net Frameworkには、Streamから派生する複数のクラスが存在します。 その中のStreamReaderを使用して、アプリケーションで、テキストファイルを読み込む方法について学びます。
StreamReader クラスの使い方を理解するために最初に行うことは、msdnに紹介されている使用例を実際に動かして見ることです。
C#では、いろいろなターゲットが存在し、参照設定など、使っている環境の設定も様々なので、サンプルコードも実際に使っている開発環境で本当に動作するか確認することが大切です。
では、使用例を実際に動作させてみることにします。
使用例の説明です。
以下の例は、ファイルからテキストを読み込むために、StreamReaderのインスタンスを使用します。この例で使用されるコンストラクタは、Windowsストア・アプリで使用するためのサポートはありません。
Visual Studio 2017 Community版で実行しました。

ファイル→新規作成→プロジェクトを選択します。

コンソールアプリ(.NET Framework)を選択します。
Program.csに使用例で示されたコードを貼り付け、コメントを日本語に訳します。
更に、以下のコードを追加します。
// Enterキーが押されるまで、コンソールを閉じないようにする
Console.Read();
コンソールアプリケーションは、VisualStudioの開発環境から実行すると、終了するとコンソールがすぐに閉じてしまい実行結果を確認できないので、キー入力を求めるコードを追加し、キー入力があるまで、アプリケションが終了しないようにします。
using System;
using System.IO;
class Test
{
public static void Main()
{
try
{
// Create an instance of StreamReader to read from a file.
// ファイルから、読み込むために、StreamReaderのインスタンスを作成します。
// The using statement also closes the StreamReader.
// また、using ステートメントは、StreamReaderを閉じます。
using (StreamReader sr = new StreamReader("TextFile.txt"))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
// ファイルの末端に達するまで、ファイルから行を読み込んで、表示します。
while ((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
// Enterキーが押されるまで、コンソールを閉じないようにする
Console.Read();
}
catch (Exception e)
{
// Let the user know what went wrong.
// ユーザーに、何が問題になったのかを知らせます。
// The file could not be read:
Console.WriteLine("ファイルを読み取れませんでした:");
Console.WriteLine(e.Message);
}
}
}

次に、読み込むテキストファイルを用意します。
ソリューションエクスプローラーから、テキストファイルを追加します。
一番上の項目を右クリックし、追加→新しい項目を選択します。

コードの記述に合わせ、「TextFile.txt」のファイル名でテキストファイルを追加します。
作成したテキストファイルに次の内容を記入し、保存します。
テキストエディタで作成する場合は、保存場所と文字エンコードに注意して下さい。
// 英語,複数形,性別,日本語,数詞
dog,dogs,male,犬,匹
bitch,bitchs,female,犬,匹
cat,cats,non,猫,匹
rabbit,rabbits,non,兎,羽

開始をクリックします。

コンソールが、すぐに閉じてしまいます。これは、キー入力を求めるコードに到達していないことを示すので、例外が発生しているのだと思います。
例外処理の最後の行に、ブレークポイントを設定します。赤い丸がブレークポイントです。

再度、実行します。ファイルに作成したテキストファイルにパスが通っていないようです。

ディバッグを停止します。

ソリューションのフォルダをエクスプローラーで開きます。

本来は、スコープの設定をして問題を解決する必要があると思うのですが、方法がわからないので、「TextFile.txt」を「Debug」フォルダ内にコピーします。

実行するとテキストが表示されます。
このプログラムでは、StreamReaderの返り値を確認して、ファイルの終端を判別しています。
StreamReaderの返り値は、読み込んだ文字列の文字数が返されます。それを利用して、文字が存在するかどうか、つまり、nullでないかを判別し、ファイルの終端を判別します。
msdnのStreamReader クラスの使用例を改変する
msdnのStreamReader クラスの使用例は、コードが短く理解しやすいのですが、このままだと使いにくいので、このコードに、コードを追加していきます。
ファイルを読み込む際の例外処理の対処
まず、例外処理のtry…catch...が動作しないように、例外が発生しないコードにします。例外処理は、処理の負荷が大きいのと対処するコードをcatchの中に記述するとコードが読みにくいので対処しにくくなるため、極力例外処理が発生しない用にすることが推奨されています。
例外 | 備考 |
---|---|
FileNotFoundException | 指定したファイルが存在しない場合発生する |
ArgumentNullException | 引数filenameがnullの場合発生する |
ArgumentException | 引数filenameが空文字列(“”)の場合発生する |
IOException | ディバイスが読み込めないなど |
DirectoryNotFoundException | ディレクトリが存在しない場合 |
最低でも開くファイルが存在しない場合の処理を用意しておく必要があります。
StreamReaderで、ファイルを開く前に、ファイルが存在するか確認し、ファイルが存在するときだけ操作するコードを追加すると、ファイルが存在しないことで発生する例外を回避することができます。ファイルが存在することを調べるには、FileクラスのExistsメソッドを使用します。
var filePath = @"TextFile.txt";
if (File.Exists(filePath))
// ファイルが存在するときだけ処理する
{
/* StreamReaderを使った処理 */
}
else
{
// ファイルを選択する処理
}
ストリームの破棄
ファイルの内容にアクセスするストリームは、OSからファイルハンドルを取得してそれを使用します。ファイルハンドルを取得したままだと、他のアプリケーションから同じファイルを操作できなくなってしまいます。使用を終了した時点で、必ず、ハンドルを閉じる必要があります。Streamクラスとそれを継承したクラスでは、IDisposableインターフェイスを実装しており、Disposeメソッドを実行するとバッファがフラッシュされ、ハンドルを閉じることができます。
※「プログラミング C# 第 7版 p477-478」より
usingステートメントを使うと、usingステートメントを抜けたときに、Disposeメソッドを実行することができるので簡単に実装することができます。先程のmsdnのStreamReader クラスの使用例では、既に、使われています。
ファイルの終端を確認する方法
ファイルの終端を確認する方法は、基本的には、1つだけ覚えておけばいいのですが、他の人が記述したコードを読む際に、どんな方法で、ファイルの終端を確認しているか意識して見たほうがいいです。
StreamReaderの返り値を確認する
先程のmsdnのStreamReader クラスの使用例では、StreamReaderの返り値が、nullかどうかを判別しています。StreamReaderの返り値は、読み込まれた文字列が返されます。
using (StreamReader sr = new StreamReader(filePath))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
// ファイルの末端に達するまで、ファイルから行を読み込んで、表示します。
while ((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
EndOfStreamプロパティを使う
EndOfStreamプロパティは、Streamクラスとそれを継承したクラスの全てに存在するわけではありませんが、EndOfStreamプロパティを使うと終了条件がコメントなしでもわかりやすくなります。
using (StreamReader sr = new StreamReader(filePath))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
// ファイルの末端に達するまで、ファイルから行を読み込んで、表示します。
while (!sr.EndOfStream)
{
line = sr.ReadLine();
Console.WriteLine(line);
}
}
Peek()メソッドを使う
Peek()メソッドを使って、終端を検出する方法です。
Peek()メソッドは、TextReader.Peek メソッドのオーバーライドで、リーダーや文字の読み取り元の状態を変更せずに、次の文字を読み取ります。 具体的には、文字コードが入ります。使用できる文字がなければ、-1 が入ります。
using (StreamReader sr = new StreamReader(filePath))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
// ファイルの末端に達するまで、ファイルから行を読み込んで、表示します。
while (sr.Peek() >= 0)
{
line = sr.ReadLine();
Console.WriteLine(line);
}
}
// Enterキーが押されるまで、コンソールを閉じないようにする
Console.Read();
文字エンコードを指定する
Windowsの文字エンコードは、現在UTF-8が標準になっているので、他の文字エンコードを使用することは、あまり機会がないと思います。しかし、従来作成されたデータでは、従来のエンコードで作成されたデータがあるので、対応する必要が出てくる可能性があります。
文字エンコードを指定するには、StreamReaderを指定する際、Text.Encodingを指定します。Text.Encodingは、System.Text内に あるので、usingを追加しておく必要があります。
文字エンコード | Encoding |
---|---|
ASCIIコード | Encoding.ASCII |
使用OSの標準文字コード | Encoding.Default |
Unicode | Encoding.Unicode |
UTF8コード | Encoding.UTF8 |
Shift-JIS | Encoding.GetEncoding("shift_jis") |
紹介した変更を導入したコードを示します。
using System;
using System.IO;
using System.Text;
class Test
{
public static void Main()
{
try
{
// Create an instance of StreamReader to read from a file.
// ファイルから、読み込むために、StreamReaderのインスタンスを作成します。
// The using statement also closes the StreamReader.
// また、using ステートメントは、StreamReaderを閉じます。
var filePath = @"TextFile.txt";
if (File.Exists(filePath))
// ファイルが存在するときだけ処理する
{ /* StreamReaderを使った処理 */
using (StreamReader sr = new StreamReader(filePath, Encoding.UTF8))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
// ファイルの末端に達するまで、ファイルから行を読み込んで、表示します。
while (sr.Peek() >= 0)
{
line = sr.ReadLine();
Console.WriteLine(line);
}
}
// Enterキーが押されるまで、コンソールを閉じないようにする
Console.Read();
}
else
{
Console.WriteLine("ファイル「{0}」が存在しません。", filePath);
}
}
catch (Exception e)
{
// Let the user know what went wrong.
// ユーザーに、何が問題になったのかを知らせます。
// The file could not be read:
Console.WriteLine("ファイルを読み取れませんでした:");
Console.WriteLine(e.Message);
}
}
}
