🖥️

【C言語超入門】 第26回 テキストファイル

2024/12/25に公開

https://youtu.be/CbDGRn4b0vs

四国めたん
\textcolor{pink}{四国めたん: }教師役ですわ

ずんだもん
\textcolor{lime}{ずんだもん: }生徒役なのだ

\footnotesize \textcolor{pink}{四国めたん:} 皆さん、こんにちは。四国めたんです

\footnotesize \textcolor{lime}{ずんだもん:} ずんだもんなのだ。こんにちはなのだ

\footnotesize \textcolor{pink}{四国めたん:} 今回もC言語のお勉強をしていきましょう

\footnotesize \textcolor{lime}{ずんだもん:} レッツゴーなのだ

\footnotesize \textcolor{pink}{四国めたん:} 前前回は日本語の文字列に対する操作についてお話ししましたわ

\footnotesize \textcolor{lime}{ずんだもん:} Visual Studio特有の関数が多かったのだ

\footnotesize \textcolor{pink}{四国めたん:} 今回は、日本語を含めた文字列をファイルに出力したり、ファイルから入力したりする方法をお話ししますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルの入出力は大切なのだ

\footnotesize \textcolor{pink}{四国めたん:} そうですわね

\footnotesize \textcolor{lime}{ずんだもん:} ところで文字列の入出力のみなのか?

\footnotesize \textcolor{pink}{四国めたん:} ファイルに関しては、文字列だけではなく int型double型 の配列、構造体などの値を入出力することも可能ですわ

\footnotesize \textcolor{pink}{四国めたん:} それは次回に説明するので、もう少し待ってくださいね

\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ

ファイルをオープンします

\footnotesize \textcolor{pink}{四国めたん:} ファイルの読み書きを行うためには、まずファイルをオープンする必要がありますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルをオープンしないと無理なのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、通常はオープンせずに読み書きすることはできませんわ

\footnotesize \textcolor{lime}{ずんだもん:} どのようにオープンするのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルのオープンはfopen関数によって行いますわ

\footnotesize \textcolor{lime}{ずんだもん:} 関数の形式を教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} 形式としてはFILE* fopen(const char* filename, const char* mode)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 説明をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} まず、filenameにオープンするファイルの名前をセットしますわね

\footnotesize \textcolor{lime}{ずんだもん:} ファイルの名前には日本語も使えるのか?

\footnotesize \textcolor{pink}{四国めたん:} いちおう、使えますわね

\footnotesize \textcolor{pink}{四国めたん:} そしてmodeにはファイルをどのようにオープンするかを文字列としてセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのような文字列なのだ?

\footnotesize \textcolor{pink}{四国めたん:} 詳細は後ほど説明しますわね

\footnotesize \textcolor{pink}{四国めたん:} 最後に、戻り値は FILE型 のポインタですわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイル型

\footnotesize \textcolor{pink}{四国めたん:} これも後ほど説明しますわね

\footnotesize \textcolor{lime}{ずんだもん:} 少し待つのだ

\footnotesize \textcolor{pink}{四国めたん:} なお、ファイルのオープンに失敗するとNULLが返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} とりあえずプログラムを作成して実行する前に、ファイルを置く場所を作りましょう

\footnotesize \textcolor{lime}{ずんだもん:} ファイルを置く場所?

\footnotesize \textcolor{pink}{四国めたん:} はい、Cドライブ直下に"temp"フォルダを作成しておきますわ

フォルダの作成

フォルダ

\footnotesize \textcolor{lime}{ずんだもん:} Cドライブ直下にファイルを置いてはダメなのか?

\footnotesize \textcolor{pink}{四国めたん:} 昔はできたのですが、今はCドライブ直下に、直接、ファイルを作成するのは難しいですわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} フォルダができたらプログラムを実行してみましょう

#include <stdio.h>

void main() {
  FILE* pf = fopen("C:\\temp\\テスト.txt", "w");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました\n");
  } else {
    printf("ファイルのオープンに失敗しました\n");
  }
}

ファイル作成の結果

ファイル作成後のフォルダ

\footnotesize \textcolor{lime}{ずんだもん:} "テスト"?ファイルが作成されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、今回は文字列を書き込むためにファイルをオープンしましたわ

\footnotesize \textcolor{lime}{ずんだもん:} 拡張子".txt"が付いていないようだが、いいのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、デフォルトでは拡張子は表示されませんので注意が必要ですわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルの種類が表示されているので、それで判断するしかないのか

\footnotesize \textcolor{pink}{四国めたん:} ファイルの種類で確認するか、設定を変えるかですわね

\footnotesize \textcolor{lime}{ずんだもん:} ところで、今回のようにファイルが存在していない場合は、どうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} その場合には新規に作成されますわね

\footnotesize \textcolor{pink}{四国めたん:} ちなみに文字列を読み出すためにファイルをオープンする場合で、ファイルが存在しなければNULLが返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} つまり、エラーということか

\footnotesize \textcolor{pink}{四国めたん:} なお、このプログラムは不完全ですわね

\footnotesize \textcolor{lime}{ずんだもん:} どこが不完全なのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルをオープンしたら、必ずクローズする必要があるのですわ

\footnotesize \textcolor{lime}{ずんだもん:} あぁ、ファイルのクローズが無いのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} それではfopenの引数について、説明を続けますわね

\footnotesize \textcolor{lime}{ずんだもん:} おねがいするのだ

filenameにファイル名を指定します

\footnotesize \textcolor{pink}{四国めたん:} まず、filenameにはオープンするファイルの名前をセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイル名に決まりはあるのか?

\footnotesize \textcolor{pink}{四国めたん:} 一部、使えない記号がありますが、ファイル名はかなり自由に決めることができますわ

\footnotesize \textcolor{lime}{ずんだもん:} 使えない記号?

\footnotesize \textcolor{pink}{四国めたん:} はい、このような文字ですわ

  • 円記号(\small\yen)、もしくはバックスラッシュ(\small\backslash)
  • 斜線、スラッシュ(/)
  • コロン(:)
  • アスタリスク(*)
  • 疑問符、クエスチョンマーク(?)
  • ダブルクォーテーション(")
  • 不等号(<>)
  • 縦線、パイプライン(|)

\footnotesize \textcolor{lime}{ずんだもん:} 結構、あるのだ

\footnotesize \textcolor{pink}{四国めたん:} それと、ファイル名には 拡張子 が付きますが、一般的なテキストファイルの拡張子は".txt"を使いますわね

\footnotesize \textcolor{lime}{ずんだもん:} 他の拡張子は使えないのか?

\footnotesize \textcolor{pink}{四国めたん:} いえ、他の拡張子でも問題はありませんわ

\footnotesize \textcolor{pink}{四国めたん:} それから、ファイル名にはディレクトリも含めることができますわ

\footnotesize \textcolor{lime}{ずんだもん:} サンプルのプログラムでもディレクトリを含めていたのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{lime}{ずんだもん:} ところでディレクトリの区切りはバックスラッシュもしくは円マークが2重になっていたが、なぜなのだ?

\footnotesize \textcolor{pink}{四国めたん:} いい所に気が付きましたわね

\footnotesize \textcolor{pink}{四国めたん:} 通常は、Windowsでのディレクトリの区切りはバックスラッシュ"\small\backslash"もしくは円マーク"\small\yen"ですわ

\footnotesize \textcolor{pink}{四国めたん:} ですが、文字列中では2重のバックスラッシュ"\small\backslash\small\backslash"もしくは円マーク"\small\yen\small\yen"としてバックスラッシュや円マークを2つ重ねますわ

\footnotesize \textcolor{lime}{ずんだもん:} なぜなのだ?

\footnotesize \textcolor{pink}{四国めたん:} 文字列中のバックスラッシュ"\small\backslash"もしくは円マーク"\small\yen"はエスケープシーケンスの一部と見なされるのですわ

\footnotesize \textcolor{lime}{ずんだもん:} あぁ、改行文字"\small\backslashn"と同じ扱いなのか...

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} つまり、エスケープシーケンスとして、バックスラッシュ"\small\backslash"もしくは円マーク"\small\yen"は二重にして"\small\backslash\small\backslash"や"\small\yen\small\yen"として記述するのですわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

フォルダの区切り

Windowsでは、フォルダの区切り文字の指定は、バックスラッシュ"\small\backslash"もしくは円マーク"\small\yen"は二重にして"\small\backslash\small\backslash"もしくは"\small\yen\small\yen"として記述します

ですが、LinuxなどのUnix系OSでのフォルダの区切り文字の指定は、スラッシュ"/"なので、エスケープシーケンスを使う必要がなく、シンプルです

最近のVisual Studioでは、Unix系OSでのフォルダの区切り文字の指定でも問題なく動作するようになりました

ですので、フォルダの区切り文字の指定は、バックスラッシュもしくは円マークではなく、スラッシュを使うようにした方がいいかもしれません

例えば、FILE* pf = fopen("C:/temp/テスト.txt", "w");のような感じになります

modeにオープンモードを設定します

\footnotesize \textcolor{pink}{四国めたん:} 次に、modeにはファイルのオープン方法を文字列で指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのような文字列を使うのだ?

\footnotesize \textcolor{pink}{四国めたん:} 色々とあるのですが、テキストファイルで良く使うのは3つのモードですわ

モード

mode 意味
"w" 文字列の書き出し専用としてオープン
"r" 文字列の読み込み専用としてオープン
"a" 文字列の追加書き出し専用としてオープン

\footnotesize \textcolor{lime}{ずんだもん:} 1文字だけなのだが...

\footnotesize \textcolor{pink}{四国めたん:} テキストファイルでは1文字ですわね

\footnotesize \textcolor{lime}{ずんだもん:} それぞれのモードについて説明してほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ

\footnotesize \textcolor{pink}{四国めたん:} まず、modeが"w"の場合には、文字列の書き出し専用としてファイルをオープンしますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルが存在しない場合は新しく作成されるとして、既にファイルが存在する場合は、どうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} 指定のファイルが既に存在する場合には上書きされますわ

\footnotesize \textcolor{lime}{ずんだもん:} 気を付けるのだ

\footnotesize \textcolor{pink}{四国めたん:} 次にmodeが"r"の場合には、文字列の読み込み専用としてファイルをオープンしますわ

\footnotesize \textcolor{lime}{ずんだもん:} 指定のファイルが存在しない場合には、どうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルのオープンが失敗して、戻り値がNULLとなりますわね

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} 最後にmodeが"a"の場合にも、"w"と同じく文字列の書き出し専用としてファイルをオープンしますわ

\footnotesize \textcolor{lime}{ずんだもん:} "w"との違いはなんなのだ?

\footnotesize \textcolor{pink}{四国めたん:} "w"では既存のファイルに上書きされてしまうのに対して、"a"では既存のファイルの最後から文字列を追加しますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほど、"a"はaddの"a"か

\footnotesize \textcolor{pink}{四国めたん:} いいえ、appendの"a"だったかと...

\footnotesize \textcolor{lime}{ずんだもん:} ところでmodeが"a"の場合に、指定のファイルが存在しない場合はどうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} "w"と同様、指定のファイルが存在しなければ、新たに作成されますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

ファイルの同時読み書き

戻り値はFILE型のポインタです

\footnotesize \textcolor{pink}{四国めたん:} fopenFILE型 のポインタを戻しますわ

\footnotesize \textcolor{lime}{ずんだもん:} FILE型

\footnotesize \textcolor{pink}{四国めたん:} はい、 FILE型 はファイルを扱う際に使用する ハンドル で、特別な構造体ですので大文字で表記されますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのような構造体なのだ?

\footnotesize \textcolor{pink}{四国めたん:} C標準ライブラリで定義された独自の型ですわね

\footnotesize \textcolor{pink}{四国めたん:} なお、構造体の内容についてはシステム毎に異なっているので、あまり気にする必要はありませんわ

\footnotesize \textcolor{lime}{ずんだもん:} とりあえずスルーしておくのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみにfopenで取得した FILE型 のポインタは、ファイルを操作する時には必ず指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 重要なのだ

最後はファイルをクローズしましょう

\footnotesize \textcolor{pink}{四国めたん:} ファイルをオープンしたら必ずクローズしましょう

\footnotesize \textcolor{lime}{ずんだもん:} どのようにクローズするのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルのクローズはfclose関数によって行いますわ

\footnotesize \textcolor{lime}{ずんだもん:} fclose関数?

\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはint fclose(FILE* stream)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 詳しい説明をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} streamにはfopen関数で取得した FILE型 のポインタを指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{lime}{ずんだもん:} ちなみにNULLは指定できるのか?

\footnotesize \textcolor{pink}{四国めたん:} 基本的にはできませんわね

\footnotesize \textcolor{pink}{四国めたん:} また、戻り値は、クローズが成功すれば0、失敗すればそれ以外の値が返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} つまり、戻り値をif文などの条件式に使えるということか...

\footnotesize \textcolor{pink}{四国めたん:} 鋭いですわね

\footnotesize \textcolor{pink}{四国めたん:} なお、一旦ファイルをクローズすると、ファイルへの操作、例えば読み書きはできませんので注意が必要ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 再度、オープンする必要があるのか?

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} ちなみに前のサンプルが不完全だった理由はfcloseでファイルをクローズしていなかったからですわ

\footnotesize \textcolor{lime}{ずんだもん:} 修正が必要なのだ

#include <stdio.h>

void main() {
  FILE* pf = fopen("C:\\temp\\テスト.txt", "w");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました\n");
    fclose(pf);
    pf = NULL;
  } else {
    printf("ファイルのオープンに失敗しました\n");
  }
}

ファイルのクローズ

\footnotesize \textcolor{lime}{ずんだもん:} 「ファイルのオープンに成功しました」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} 今回は、既存のファイルをオープンしましたので、上書きになりますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルのオープンが失敗した場合にはfcloseは呼び出していないのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、ファイルのオープンが失敗した場合にはNULLが返るので、fclose に渡す事はできませんわ

ファイルに文字列を書き出します

\footnotesize \textcolor{pink}{四国めたん:} 前のサンプルでは、ファイルをオープンしてクローズするだけでしたわ

\footnotesize \textcolor{lime}{ずんだもん:} 文字列を書き出したり、読み込んだりはしていなかったのだ

\footnotesize \textcolor{pink}{四国めたん:} 次は、オープンしたファイルに文字列を書き出してみようと思いますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのようにして書き出すのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルへの文字列の書き出しは、幾つかの関数で可能ですわ

\footnotesize \textcolor{lime}{ずんだもん:} いくつもあるのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、そのうちの簡単な2つの関数fprintffputsについてお話ししますわ

\footnotesize \textcolor{lime}{ずんだもん:} おねがいするのだ

fprintf

\footnotesize \textcolor{pink}{四国めたん:} まずはfprintfですわ

\footnotesize \textcolor{lime}{ずんだもん:} 似たような関数でprintfをよく使ってきたが、何か関係があるのか?

\footnotesize \textcolor{pink}{四国めたん:} たしかにfprintfprintfと同じように、指定した書式で文字列を出力しますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほど...

\footnotesize \textcolor{pink}{四国めたん:} ただ、違いは出力先がファイルかコンソールかだけですわ

\footnotesize \textcolor{lime}{ずんだもん:} 形式もおなじなのか?

\footnotesize \textcolor{pink}{四国めたん:} いえ、形式はint fprintf(FILE* stream, const char* format [, argument] ...)となりますわね

\footnotesize \textcolor{lime}{ずんだもん:} 引数に FILE型 のポインタstreamが追加されているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、streamにはfopenで取得したファイルハンドルをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} formatargumentprintfと同じなのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、format内では 書式指定子 も使用できますわ

\footnotesize \textcolor{lime}{ずんだもん:} 戻り値もprintfと同じなのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、戻り値は、出力が成功すれば出力されたバイト数、失敗すれば負数のエラーコードが返りますわね

\footnotesize \textcolor{lime}{ずんだもん:} 文字数ではないのか?

\footnotesize \textcolor{pink}{四国めたん:} 成功時に返るのはバイト数であって、文字数ではありませんわね

\footnotesize \textcolor{pink}{四国めたん:} ですので、日本語を出力する際には注意が必要ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 具体例をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} とりあえずforループで0~9までの数字をファイルに書き出すプログラムですわ

#include <stdio.h>

void main() {
  FILE* pf = fopen("C:\\temp\\テスト.txt", "w");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました\n");

    for (int i = 0; i < 10; i++) {
      fprintf(pf, "カウンター%d\n", i);
    }

    fclose(pf);
    pf = NULL;
  } else {
    printf("ファイルのオープンに失敗しました\n");
  }
}

fprintfの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「ファイルのオープンに成功しました」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、"テスト.txt"には「カウンター0」~「カウンター9」の数字が書き出されているはずですわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルを メモ帳 でオープンして確認してみるのだ

ファイル内容

\footnotesize \textcolor{lime}{ずんだもん:} たしかに「カウンター0」~「カウンター9」の数字が書き出されているのだ

fprintfとprintfの関係

実はprintfは基本的にfprintfと同じ関数です

fprintfのファイルハンドルとしてstdoutを指定するとprintfと同じ動作となります

なおstdoutはC標準ライブラリで予め定められたファイルハンドルで、コンソールが対象です

ちなみにここで云う ファイル はディスク上に存在するファイル以外に、コンソールやネットワークなどのデバイスなどを含みます

stdoutのオープンやクローズは自動的に行われるので、そのままfprintfのファイルハンドルとして使用できますわ

#include <stdio.h>

void main() {
  fprintf(stdout, "標準出力は既にオープンしています\n");

  for (int i = 0; i < 10; i++) {
    fprintf(stdout, "カウンター%d\n", i);
  }
}

コンソールへの出力は以下のようになります

標準出力は既にオープンしています
カウンター0
カウンター1
カウンター2
カウンター3
カウンター4
カウンター5
カウンター6
カウンター7
カウンター8
カウンター9

fputs

\footnotesize \textcolor{pink}{四国めたん:} 次はfputsですわ

\footnotesize \textcolor{lime}{ずんだもん:} fputs

\footnotesize \textcolor{pink}{四国めたん:} はい、ファイルに文字列をそのまま書き出しますわ

\footnotesize \textcolor{lime}{ずんだもん:} fprintfとは違うのか?

\footnotesize \textcolor{pink}{四国めたん:} fprintfとは異なり、fputsでは書式等の指定はできませんわね

\footnotesize \textcolor{lime}{ずんだもん:} そうなのか...

\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはint fputs(const char* str, FILE* stream)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 詳しく教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} まず、strには書き出す文字列をセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} fprintfと同じではないのか?

\footnotesize \textcolor{pink}{四国めたん:} いいえ、ここで指定した文字列は、そのままファイルに書き出されますわ

\footnotesize \textcolor{lime}{ずんだもん:} つまり、書式指定子などは使えないのか

\footnotesize \textcolor{pink}{四国めたん:} はい、使えませんわね

\footnotesize \textcolor{pink}{四国めたん:} そしてstreamfopenで取得したファイルハンドルをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} おや?ファイルハンドルは最後の引数にセットするのか...

\footnotesize \textcolor{pink}{四国めたん:} はい、fprintfとは位置が異なっているので注意する必要がありますわ

\footnotesize \textcolor{pink}{四国めたん:} そして、戻り値には、書き出しが成功すれば負ではない整数、失敗すれば EOF が返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} 書き出されたバイト数ではないのだな

\footnotesize \textcolor{pink}{四国めたん:} そうですわね

\footnotesize \textcolor{lime}{ずんだもん:} ところで EOF とは何なのだ?

\footnotesize \textcolor{pink}{四国めたん:} "End Of File"の略で、"stdio.h"では負数、通常は-1で定義されている定数ですわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} とりあえずfputsで文字列を書き出してみますわね

#include <stdio.h>

void main() {
  char c[] = "これはpenです。\n";
  FILE* pf = fopen("C:\\temp\\テスト1.txt", "w");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました\n");

    fputs(c, pf);

    fclose(pf);
    pf = NULL;
  } else {
    printf("ファイルのオープンに失敗しました\n");
  }
}

fputsの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「ファイルのオープンに成功しました」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、"テスト1.txt"には「これはpenです。」と書き出されているはずですわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイル名を"テスト1.txt"に変えているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、"テスト.txt"を残しておきたいので変えましたわ

\footnotesize \textcolor{lime}{ずんだもん:} さっそくファイルを メモ帳 でオープンして確認してみるのだ

ファイル内容2

\footnotesize \textcolor{lime}{ずんだもん:} たしかに「これはpenです。」と書き出されているのだ

ファイルから文字列を読み込みます

\footnotesize \textcolor{lime}{ずんだもん:} ファイルに文字列を書き出すことができたら、次はファイルから文字列を読み込むのだ

\footnotesize \textcolor{pink}{四国めたん:} そうですわね

\footnotesize \textcolor{lime}{ずんだもん:} どうやってファイルから文字列を読み込むのだ?

\footnotesize \textcolor{pink}{四国めたん:} まず、fopenでモードを"r"にしてファイルをオープンしますわ

\footnotesize \textcolor{lime}{ずんだもん:} うむ、まずはファイルのオープンなのだ

\footnotesize \textcolor{pink}{四国めたん:} そして、ファイルから文字列の読み込むための関数は、幾つかありますわ

\footnotesize \textcolor{lime}{ずんだもん:} 複数の関数があるのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、今回は一番簡単な関数fgetsについてお話ししますわね

\footnotesize \textcolor{lime}{ずんだもん:} 他の関数の説明はないのか?

\footnotesize \textcolor{pink}{四国めたん:} 例えばfscanfと云うfprintfの対になるような書式付き読み込み関数もありますが、使い勝手が悪いのですわ

\footnotesize \textcolor{lime}{ずんだもん:} 使い勝手が悪いならスルーするに限るのだ

fgets

\footnotesize \textcolor{pink}{四国めたん:} fgetsは、ファイルから文字列を読み込みますわ

\footnotesize \textcolor{lime}{ずんだもん:} fputsとは逆なのか

\footnotesize \textcolor{pink}{四国めたん:} はい、文字列の書き出しと読み込みで対になっていますわね

\footnotesize \textcolor{lime}{ずんだもん:} 詳しく教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはchar* fgets(char* str, int num, FILE* stream)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほど...

\footnotesize \textcolor{pink}{四国めたん:} strには読み込んだ文字列を収容するためのメモリ領域へのポインタをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} char型 の配列やmallocで取得したメモリ領域をセットすればOKなのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} そして、numには読み込む文字列の(最大のバイト数+1)を指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} なぜ1が足されているのだ?

\footnotesize \textcolor{pink}{四国めたん:} 1だけ多く設定するのは最後にNUL終端が付加されるからですわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみにnumにセットする値は、strにセットするメモリ領域のサイズ以下でなければなりませんわ

\footnotesize \textcolor{lime}{ずんだもん:} どうしてなのだ?

\footnotesize \textcolor{pink}{四国めたん:} numstrのメモリ領域のサイズより大きな値をセットすると、他のデータを破壊する場合があるからですわ

\footnotesize \textcolor{lime}{ずんだもん:} うう、それはダメなのだ

\footnotesize \textcolor{pink}{四国めたん:} streamにはfopenで取得したファイルハンドルをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} これはfputsと同じなのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、ファイルハンドルをセットする引数の位置が最後になっていますわね

\footnotesize \textcolor{lime}{ずんだもん:} 戻り値はfputsと違って、 int型 ではなくて、 char型 のポインタなのだな

\footnotesize \textcolor{pink}{四国めたん:} そうですわね

\footnotesize \textcolor{pink}{四国めたん:} 読み込みが成功すればstrが、失敗すればNULLが返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのように動作するかを教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} まず、fgetsを呼び出す毎に、(指定した文字列のバイト数-1)バイト分が読み込まれますわ

\footnotesize \textcolor{lime}{ずんだもん:} 常にそのバイト数が読み込まれるのか?

\footnotesize \textcolor{pink}{四国めたん:} いいえ、改行文字が読み込まれるか、ファイルの最後に到達するかでも読み込みが終了しますわ

\footnotesize \textcolor{lime}{ずんだもん:} つまり、メモリサイズが十分なら、1行ごとに読み込まれるということか

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} そして、読み込んだ後の文字列の最後には、必ずNUL終端が付加されますわ

\footnotesize \textcolor{lime}{ずんだもん:} ところで改行文字も読み込まれるのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、改行文字も読み込まれますわ

\footnotesize \textcolor{pink}{四国めたん:} それでは実際のプログラムを見てみましょう

\footnotesize \textcolor{pink}{四国めたん:} 実行する際にはfprintfで出力した"テスト.txt"ファイルが存在することが前提ですわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルの内容は「カウンター0」から「カウンター9」までの羅列だったのだ

#include <stdio.h>

#define SIZE (20)

void main() {
  FILE* pf = fopen("C:\\temp\\テスト.txt", "r");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました\n");

    char c[SIZE] = {0};
    char* p = fgets(c, SIZE, pf);

    while (p != NULL) {
      printf("%s", p);
      p = fgets(c, SIZE, pf);
    }

    fclose(pf);
    pf = NULL;
  } else {
    printf("ファイルのオープンに失敗しました\n");
  }
}

fgetsの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「ファイルのオープンに成功しました」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、その後に「カウンター0」~「カウンター9」が表示されていますわ

\footnotesize \textcolor{lime}{ずんだもん:} プログラムの説明をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、まずfopenをモード"r"で呼び出して、ファイルをオープンしていますわ

\footnotesize \textcolor{lime}{ずんだもん:} 戻り値がNULLかどうかで、ファイルのオープンが成功しているかをチェックしているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、その後に要素数が20の char型 の配列を準備しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 要素数は20でいいのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、「カウンター0」などの文字列は11バイトですから、12バイトあれば問題ないですわ

\footnotesize \textcolor{pink}{四国めたん:} そして、最初のfgetsの呼び出しを行いますわ

\footnotesize \textcolor{lime}{ずんだもん:} numとしてSIZEを指定しているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、配列のサイズですわね

\footnotesize \textcolor{pink}{四国めたん:} その後、fgetsからNULLが返るまで、読み込んだ文字列の出力とfgetsの呼び出しを繰り返しますわ

\footnotesize \textcolor{lime}{ずんだもん:} fgetsからNULLが返るということは、ファイルの終わりまで、読み込んだということか

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} そして、最後にfcloseでファイルを閉じますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルを閉じるのは大事なのだ

fscanf

ファイルからの文字列の読み込みについては、fprintfの対になるような書式付き読み込み関数fscanfがあります

書式に合わせて、ファイルから文字列を読み込みますので、文字列の書式をしっかりと認識している必要があります

ですので、基本的にはfprintfで書き出した文字列を、そのままの書式で読みだすことになります。

形式はint fscanf(FILE* stream, const char* format, ...)となります

まず、streamにはfopenで取得したファイルハンドルをセットします

formatには書式指定子を含む文字列を指定します

formatに続く引数には、書式指定子で指定した値を代入する変数へのポインタを列挙します

とりあえず、"テスト.txt"を読み込んで、カウンターの値(0~9)を取得するプログラムを見てみましょう

#include <stdio.h>

void main() {
  FILE* pf = fopen("C:/temp/テスト.txt", "r");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました\n");

    int num = 0;
    for (int i = 0; i < 10; i++) {
      int s = fscanf(pf, "カウンター%d\n", &num);
      printf("%d, 取得した値は%dです。\n", s, num);
    }

    fclose(pf);
    pf = NULL;
  } else {
    printf("ファイルのオープンに失敗しました\n");
  }
}

forループ内でfscanfを実行し、得られた値をコンソールに表示しています

fscanfの戻り値"s"は、取得した値の数なので、常に1となります

fscanfformatの部分は、fprintfで使用した文字列"カウンター%d\n"と同じです

値が代入される引数は、"num"のアドレスがセットされていることに注意して下さい

ちなみに"カウンター%d\n"を"カウント%d\n"などとすると、ファイル内の文字列と合わなくなるので、数値"num"の取得に失敗します

まとめ

\footnotesize \textcolor{pink}{四国めたん:} お疲れさまでした

\footnotesize \textcolor{lime}{ずんだもん:} おつかれさまなのだ

\footnotesize \textcolor{pink}{四国めたん:} 以上で テキストファイル についての説明は終わりですわ

Discussion