★ファイル操作(テキストファイル6)★


ゲームなどでは、文章をファイルに書いておき、読み込んで使うケースがよくあります。

今回は文章の読み込みと表示を行ってみます。

まずはデータを準備しましょう。

決まり事として、文章の1行の文字数は、全角文字で20文字までとします。

(半角で40文字分ですね)

ファイル名は「Scenario.txt」にします。

↑のように20文字を超えないように何か書いてください。


文章も何行あるか分からないケースが多いため、EOFを利用します。

今回も枠組みから作りましょう。

<sample program 117-01>

#include <stdio.h>

#define SENTENCE_MAX 41

int main(void)
{
    char sentence[SENTENCE_MAX];

    FILE* fp;

    fp = fopen("Scenario.txt", "r");

    if (fp == NULL) {
        printf("OPEN ERROR\n");
        return 1;
    }

    /* データ読み込みと表示 */
    
    fclose(fp);
    
    return 0;
}

文章は文字列ですので、char型の配列を用意します。

要素数は「全角20文字」=「半角40文字」プラス「ヌル文字」分で41個としました。

今回は、文章を読み込んだらすぐに表示します。

<sample program 117-02>

#include <stdio.h>

#define SENTENCE_MAX 41

int main(void)
{
    char sentence[SENTENCE_MAX];

    FILE* fp;

    fp = fopen("Scenario.txt", "r");

    if (fp == NULL) {
        printf("OPEN ERROR\n");
        return 1;
    }

    /* データ読み込みと表示 */

    while (!feof(fp)) {

        fscanf(fp, "%s", sentence);

        printf("%s\n", sentence);
    }
    
    fclose(fp);
    
    return 0;
}

<実行結果>

これはテスト用文章です。
続いて2行目の文章
さらに3行目の文章
これが最後の文章です。EOFはここ→
続行するには何かキーを押してください・・・

ここでも1つ気を付けて欲しいことがあります。

文章を変えてみますね。

英語の文章を1行追加しました。

それでは実行してみましょう。

<実行結果>

これはテスト用文章です。
続いて2行目の文章
さらに3行目の文章
It
is
well
written.
これが最後の文章です。EOFはここ→
続行するには何かキーを押してください・・・

scanf系の関数にとっては、「半角空白」も「区切り文字」です。

単語と単語の間に「半角空白」が入っているため、4つに分割されてしまいました。

これは、↓のコラムでも触れました。

scanfと文字列

文字列入力関数

今回は対処方法として、fgetsを使って読み込む方法を説明します。

<sample program 117-03>

#include <stdio.h>

#define SENTENCE_MAX 41

int main(void)
{
    char sentence[SENTENCE_MAX];

    FILE* fp;

    fp = fopen("Scenario.txt", "r");

    if (fp == NULL) {
        printf("OPEN ERROR\n");
        return 1;
    }

    /* データ読み込みと表示 */

    while (!feof(fp)) {

        fgets(sentence, SENTENCE_MAX, fp);

        printf("%s\n", sentence);
    }
    
    fclose(fp);
    
    return 0;
}

<実行結果>

これはテスト用文章です。

続いて2行目の文章

さらに3行目の文章

It is well written.

これが最後の文章です。EOFはここ→
続行するには何かキーを押してください・・・

何か変な改行が入ってしまっています。

これはfgetsが改行文字まで読み込んでいることが原因です。

データには(見えませんが)1行ごとに改行文字が入っています。

fgetsは(見えない)改行文字も含めて1行読み込み、文字列の最後にヌル文字を入れます。

と言うことは、「全角20文字」=「半角40文字」+改行文字+ヌル文字の42個分の要素数が無ければ配列をオーバーしてしまいます。

このままでは、危険なので要素数を1つ増やしておきましょう。

さらに、表示する際の改行を消します。

<sample program 117-04>

#include <stdio.h>

#define SENTENCE_MAX 42

int main(void)
{
    char sentence[SENTENCE_MAX];

    FILE* fp;

    fp = fopen("Scenario.txt", "r");

    if (fp == NULL) {
        printf("OPEN ERROR\n");
        return 1;
    }

    /* データ読み込みと表示 */

    while (!feof(fp)) {

        fgets(sentence, SENTENCE_MAX, fp);

        printf("%s", sentence);
    }
    
    fclose(fp);
    
    return 0;
}

<実行結果>

これはテスト用文章です。
続いて2行目の文章
さらに3行目の文章
It is well written.
これが最後の文章です。EOFはここ→続行するには何かキーを押してください・・・

余分な改行が表示されることはなくなりましたが、最後の行は元々改行文字が無かったため改行されていません。

これは、データ側で改行を増やすことで対処しましょう。

<実行結果>

これはテスト用文章です。
続いて2行目の文章
さらに3行目の文章
It is well written.
これが最後の文章です。
これが最後の文章です。
続行するには何かキーを押してください・・・

最後の文章が2行出てしまいました・・・

改行を追加したことで、余分に1回ループしてしまったことが原因です。

最後の文章を読み込み終わった時点では、改行文字が区切り文字になっているため、まだファイルの終わりに達していません。

もう1度読み込もうとして、ファイルを終わりに気づくのです。

それでは、プログラムを書き換えてみます。

<sample program 117-05>

#include <stdio.h>

#define SENTENCE_MAX 42

int main(void)
{
    char sentence[SENTENCE_MAX];

    FILE* fp;

    fp = fopen("Scenario.txt", "r");

    if (fp == NULL) {
        printf("OPEN ERROR\n");
        return 1;
    }

    /* データ読み込みと表示 */

    for (;;){

        fgets(sentence, SENTENCE_MAX, fp);

        if (feof(fp)) {
            break;
        }

        printf("%s", sentence);
    }
    
    fclose(fp);
    
    return 0;
}

<実行結果>

これはテスト用文章です。
続いて2行目の文章
さらに3行目の文章
It is well written.
これが最後の文章です。
続行するには何かキーを押してください・・・

fgetsの後にEOFのチェックを移動することできちんと表示されるようになりました。


ファイルに限らず、なぜか思った通りに動作しないことは良くあります。

どうして動かないのか、どうやったら動くのか、考えたり調べたりすることは非常に重要です。

ファイルの場合は、データの格納の仕方が原因になるケースもありますので、色々なプログラムを組んで試してください。


次へ

戻る

目次へ