C#:テキストファイルをコレクションに読み取ってプログラムから扱う

C#コレクションのイメージ画像 C#

C#のコレクション(具体的にはListジェネリクスクラス)を使って簡単なテキストファイルを読み取り、プログラムから操作できるようにしてみます。

今回はドラクエI(懐かしいですね)に出てきたモンスターの名前が入ったテキストファイルを読み取ってコレクションで扱ってみます。
題してドラクエ簡易データベースです。

プログラムイメージ
VisualStudioファイルからコレクションに読み込むイメージの画像

アプリのイメージは、カード形式です。
進むと戻るボタンで、モンスターの名前が順番に表示されていきます。
データの最後までいったらまた最初のデータに戻る、といった処理を盛り込みます。

実行イメージ
ドラクエデータベース簡易版イメージ画像

データファイルmonsters.txtの準備

読み込みデータファイルmonsters.txtは、UTF-8で保存して

ドキュメントフォルダ >Visual Studio 2017 >Projects >ドラクエ簡易データベース >ドラクエ簡易データベース >bin >Debug

に配置してください。(Visual Studio 2017の場合)

なお、ソースコード全体とモンスター名が入ったテキストファイル(monsters.txt)は、この記事の巻末を参照するかこちらからダウンロードして使ってください。
Form1.csとmonsters.txtが入っています。

なぜListを使うか?

通常の配列やArrayListなども同じようにデータを扱えますが、Listを使った方が、データの要素数を指定しなくて済みますしデータ型も指定できるのでが柔軟に扱えます。(というか便利なのでどんどん使いましょう!)

という訳でListを使うメリット

データの要素数を気にせず扱える(Addメソッドでどんどん追加すればよい)

データ型に何を指定しても扱える(intやstringだけでなく、クラス自体も格納できる)

プロジェクトとフォームを作る

Visual Studioを起動してメニューからプロジェクトの新規作成を選び、

テンプレート >Visual C# >Windowsフォームアプリケーション

を選択します。

プロジェクト名はドラクエ簡易データベースとします。

次にフォームデザインです。

 label1(ラベル) モンスター名を表示するため
 button1(ボタン) 戻るボタン
 button2(ボタン) 進むボタン

を配置してください。

ドラクエ簡易データベースフォームデザインの画像

ラベルの文字列折り返しについて

今回は、ラベルに表示する文字列がラベルの幅をこえてしまったとき、折り返して表示するように、ラベルのAutoSizeプロパティfalseに設定しておきます。

VisualStudioラベルのAutoSize設定の画像

falseにするとラベルの幅と高さを自由に変更してフォームに配置できるようになります。

ラベルAutoSizeプロパティのデフォルトは、Trueです。
その場合、文字列のサイズに合わせてラベルが伸縮しますが文字列の折り返しはしません。
なおかつ、デザイン画面上でラベルの幅と高さの調整ができません。AutoSizeがtrueのときは文字列のサイズに応じてラベルが伸縮するためです。
また、フォームをこえる幅になるとラベルの文字が見えなくなってしまう場合があります。

今回は、ラベルに設定される文字列が長かった場合、ラベルを折り返して表示するため、AutoSizeプロパティをfalseに設定しておきます。

変数の準備と起動時の処理

F7キーでForm1.csのコードを開き、class Form1の先頭でコレクションmonstersと読み込むファイル名を保存する定数DATAFILE、保存したコレクションを特定するための添え字を表すnを宣言しておきます。

// ドラクエデータ保存用コレクション
static List<string> monsters = new List<string>();
// 読込ファイル名
const string DATAFILE = "monsters.txt";
// 表示中のモンスター番号
static int n;

次にデザイン画面上でフォームの何も選択されていない部分をダブルクリックしてフォームロードイベントコードを作成してください。

private void Form1_Load(object sender, EventArgs e)
{
	// 初期設定
	this.Text = Application.ProductName;
	label1.Text = "";
	button1.Text = "<";
	button2.Text = ">";
	n = 0;
	// データファイル読み込み
	loadDataFile();
}

起動時に
 1.ラベルやボタンなどの初期設定
 2.データファイル読み込み
を行います。

コレクションへのデータ追加の部分は今回loadDataFile()という名前でメソッド化しました。
この時点ではloadDataFile()メソッドが存在しないため実行はできません。

テキストファイルを読み取ってコレクションに格納する部分

フォームロードイベントから呼び出されるloadDataFile()メソッドをForm1クラス内に定義します。
ファイルが存在していない場合は、FileNotFoundExceptionの例外処理でラベルにメッセージとして表示させています。

private void loadDataFile()
{
	try
	{
		// ファイルを読み取り形式で開く(UTF-8形式)
		StreamReader file = new StreamReader(DATAFILE, Encoding.UTF8);
		// ファイルから1行ずつコレクションに追加
		string line = "";
		while((line = file.ReadLine()) != null)
		{
			// コレクションに追加
			monsters.Add(line);
			// コンソールで表示チェック
			Console.WriteLine(line);
		}
		file.Close();
	}
	catch (FileNotFoundException fnfe)	// ファイルが見つからない場合
	{
		Console.WriteLine(fnfe.Message);
		label1.Text = DATAFILE + " が見つかりません";
	}
	catch (Exception e)		// その他例外処理
	{
		Console.WriteLine(e.Message);
	}
	// データが存在していたら先頭のデータを表示
	if (monsters.Count > 0)
	{
		label1.Text = monsters[n];
	}
}

読み取るファイルは、1行に1つのモンスター名が保存されているファイルです。

monsters.txtイメージ

スライム
スライムべス
ドラキー
  :
りゅうおう(変身後)

実際には、ファイルを1行読み取ってコレクションに追加する、という作業をデータ数分繰り返します。(whileループの部分)

いたって単純です。
ReadLine()で1行ずつ読み取って、ListのAddメソッドでコレクションに追加しています。

// ファイルから1行ずつコレクションに追加
string line = "";
while((line = file.ReadLine()) != null)
{
	// コレクションに追加
	monsters.Add(line);
	// コンソールで表示チェック
	Console.WriteLine(line);
}

一旦この時点で実行確認してみてください。
ファイルの先頭データスライムが表示されています。

ドラクエデータベース簡易版イメージ画像

次にボタンの処理に移ります。

ボタンの戻ると進むでコレクションのデータを順番に表示する

戻るボタンと進むボタンの処理です。

今回は、button1が戻る、button2が進むとしています。
デザイン画面上の各ボタンをダブルクリックしてボタンクリックイベントコードを表示させてください。

戻るボタン(button1)

private void button1_Click(object sender, EventArgs e)
{
	if (monsters.Count == 0) return;	// データが存在しない場合何もしない
	// ひとつ前のデータを表示
	n--;
	if(n < 0)
	{
		n = monsters.Count - 1;
	}
	label1.Text = monsters[n];
}

進むボタン

private void button2_Click(object sender, EventArgs e)
{
	if (monsters.Count == 0) return;    // データが存在しない場合何もしない
	// 次のデータを表示
	n++;
	if(n >= monsters.Count)
	{
		n = 0;
	}
	label1.Text = monsters[n];
}

button1, button2ともほぼ同じ処理です。
ファイルが空だったり、ファイルが読み込まれずコレクションにデータが存在しない場合を想定して先頭でデータ存在の有無をチェックしています。

if (monsters.Count == 0) return;

配列の要素数は、Lengthですが、コレクションListの要素数の場合は、Countで取得できます。

戻る(button1)ボタンの場合は、0より小さいコレクションの添え字は存在しないため、マイナスになった時の処理としてデータの一番最後に移動するようにしています。

	if(n < 0)
	{
		n = monsters.Count - 1;
	}

-1しているのは、要素数が0から始まるため40体のモンスターなら39が一番最後のデータ(りゅうおう変身後)となります。

進むボタンでは、39(最後のデータ)をこえたら、コレクションの添え字を0にして最初のデータ(スライム)に戻るようにしています。

	if(n >= monsters.Count)
	{
		n = 0;
	}

ポイントは以上です。
だいたいイメージ出来たでしょうか?
実行して確認してください。

ところで今回は、Listに格納する型をstringとしました。
更に応用するならモンスター一体の要素(名前やHP、MP、アイテム等)を格納するMonsterクラスを作って、クラスごとListに放り込む(Addする)ことも可能です。

List<Monster> monsters = new List<Monster>();

ぜひ、挑戦してみてください。

ソースコード全体とテスト用ファイルmonsters.txt

今回のソースコード全体とファイル読み込みに使ったテキストファイル(monsters.txt)です。

コメント

タイトルとURLをコピーしました