前回は「ジェネリクス(型を後から決める)」をやりました。

今回は、ぐっと実務的に。ファイルの読み書きです。プログラムの結果を保存したり、保存したデータを読み込んだりします。

ファイルの読み書きとは、プログラムの外(ディスク)に、データを保存・取得することです。

なぜ、ファイルが必要なのか

これまで作ってきたプログラムには、ひとつ弱点がありました。プログラムを終了すると、データが全部消えることです。

変数も、List も、すべてプログラムが動いている間だけの、一時的なものでした。電源を切れば、消えてしまいます。

でも、現実には「保存しておきたい」ことがたくさんあります。

  • 入力された名簿を、次回も使いたい
  • 計算結果を、記録に残したい
  • 設定を、覚えておきたい

そこで、データをファイルとしてディスクに保存します。ファイルにしておけば、プログラムを終了しても、次に起動したとき、また読み込めます。

ノートにメモを書いておくようなもの。頭(メモリ)の中だけだと忘れるけれど、ノート(ファイル)に書いておけば、後で読み返せます。

ファイルに書き込む

文字列をファイルに保存するのは、一言で書けます。

File.WriteAllText("memo.txt", "こんにちは");

これで、memo.txt というファイルが作られ、中に「こんにちは」が書き込まれます。

  • File.WriteAllText(...) … ファイルに、文字列を丸ごと書き込む
  • 第1引数 … ファイル名
  • 第2引数 … 書き込む内容

複数行を書きたいときは、改行(\n)を入れます。

File.WriteAllText("memo.txt", "1行目\n2行目\n3行目");

ファイルから読み込む

保存したファイルを読むのも、一言です。

string text = File.ReadAllText("memo.txt");
Console.WriteLine(text);   // こんにちは
  • File.ReadAllText(...) … ファイルの中身を、丸ごと文字列で読み込む

書き込んだ「こんにちは」が、ちゃんと読み込めました。プログラムを一度終了して、また起動しても、ファイルは残っているので読めます。データが、保存されたわけです。

行ごとに扱う

名簿のように「1行に1件」のデータは、行ごとの配列として読み書きできます。

// 書き込む(配列を、行ごとに保存)
string[] names = { "山田", "田中", "佐藤" };
File.WriteAllLines("names.txt", names);

// 読み込む(行ごとに、配列で受け取る)
string[] loaded = File.ReadAllLines("names.txt");

foreach (string name in loaded)
{
    Console.WriteLine(name);   // 山田、田中、佐藤
}
  • WriteAllLines … 配列を、1行ずつファイルに書く
  • ReadAllLines … ファイルを、1行ずつ配列で読む

第11回の配列、第13回の foreach が、ここで活きていますね。

例外処理と、セットで使う

ここで、第27回の例外処理を思い出してください。ファイル操作は、エラーが起きやすい代表例です。

  • 読もうとしたファイルが、存在しない
  • 書き込もうとしたが、権限がない
  • ディスクがいっぱい

これらは、自分のコードが正しくても起きうる、「外の世界」のエラーです。だから、try-catch で囲むのが基本です。

try
{
    string text = File.ReadAllText("memo.txt");
    Console.WriteLine(text);
}
catch (Exception ex)
{
    Console.WriteLine("ファイルを読めませんでした:" + ex.Message);
}

第27回で「外の世界とのやりとりに、例外処理」と書きました。ファイル操作は、まさにその代表です。ここで、点が繋がります。

つまずきポイント

初心者がはまるのが、ファイルの場所(パス)です。

File.ReadAllText("memo.txt");   // どこの memo.txt?

ファイル名だけ書くと、「プログラムが動いている場所」のファイルを探します。思った場所と違うと、「ファイルが無い」エラーになります。

確実にするには、場所をフルで指定する方法もあります。

File.ReadAllText(@"C:\data\memo.txt");   // 場所をはっきり指定

@ は、文字列の中の \ をそのまま扱うための印です。Windowsのパスでよく使います。)

「ファイルが見つからない」エラーが出たら、まず「そのファイル、本当にその場所にある?」を確認してみてください。

まとめ

ファイルの読み書きで、データを保存・取得できる。

File.WriteAllText("memo.txt", "こんにちは");      // 書く
string text = File.ReadAllText("memo.txt");      // 読む

File.WriteAllLines("names.txt", names);          // 配列を行ごとに書く
string[] loaded = File.ReadAllLines("names.txt"); // 行ごとに読む
  • プログラムを終了しても、データを残せる
  • 行ごとのデータは、配列で読み書きできる
  • ファイル操作は、例外処理(try-catch)とセットで
  • パス(場所)に注意

次回は、時間のかかる処理を、待たずに進める async/await(非同期処理) です。少し難しいですが、現代のプログラミングでは欠かせない仕組みです。