ファイルの書き込み

ファイル処理2

テキストファイルへの書き込みを行うには、fprintf関数を使用します。

#include <stdio.h>
#include <string.h>

#define BUFFER 256

int main()
{
    printf("保存する文字列を入力してください\n");

    char output[BUFFER];
    fgets(output, BUFFER, stdin);
    if (output[strlen(output) - 1] != '\n')
        while (getchar() != '\n');

    FILE *fp;
    const char *file = "C:\\test.txt";

    //fp = fopen(file, "w");
    fopen_s(&fp, file, "w");

    if (fp == NULL)
    {
        printf("%sのオープンに失敗しました。\n", file);
        printf("Enterキーで終了。\n");
        getchar();
        return 0;
    }

    fprintf(fp, output);

    fclose(fp);

    printf("%sに保存しました\n", file);
    getchar();
}

このコードは、キーボードから文字列を受け取り、それを「C:\test.txt」に保存するサンプルです。

まず、11行目ではキーボードから文字列を受け取るためにfgets関数を使用しています。
ファイルの読み込みの項でも説明しましたが、fgets関数は第一引数に「stdin」を指定することで、標準入力からキーボード入力を受け取ることができます。

標準入力の読み捨て

サンプルコードでは英数字255文字分の文字列配列を用意していますが、これを超える入力があった場合には無視するようにしています。
(1文字少ないのはNULL文字が入るため)

256文字以上の入力があった場合、標準入力には読み取れなかった文字が残ってしまいますから、これを読み捨てる必要があります。
(厳密には、改行も1文字となるので255文字以上の入力があった場合です)
そのための処理が12、13行目です。

まずstrlen関数で、入力を受け取った文字列配列の文字数を調べます。
strlen関数で得られるのはNULL文字までの文字数です。
NULL文字のひとつ手前が改行コード以外であれば、標準入力内に何らかの文字が残っていることがわかります。
その場合、while文で改行コードが出現するまで標準入力から文字を読み捨てます。

12行目の書き方がややこしいかもしれないので、二行に分割した場合を以下に示します。

if (output[strlen(output) - 1] != '\n')
//↓
int length = strlen(output);
if (output[length - 1] != '\n')

fprintf関数

受け取った文字列をテキストファイルに書き込む処理は単純です。

まず、fopen関数(fopen_s関数)の第三引数に「w」を指定し、ファイルを書き込みモードで開きます。
指定のファイルが存在しない場合には自動的に作成されます。

ファイルを書き込みモード(w)で開く場合、指定のファイルが既に存在するとそのファイルは上書きされてしまうので注意してください。

そして、fprintf関数ではfopen関数で受け取ったファイルポインタを第一引数に指定します。
この関数はprintf関数と非常によく似ています。

int fprintf(
 FILE *stream,
 const char *format [,
 argument ]...
);
ファイルストリームstreamに文字列formatを書き込む。
戻り値は書き込んだ文字数。
失敗した場合は負数を返す。

fprintf関数は、printf関数の出力先を変更できる版です。
printf関数より引数がひとつ増え、出力先を指定できるようになっています。
ここにファイルポインタを指定すると、そのファイルへ文字列を出力(つまり書き込み)ができます。

printf関数とほどんど同じですから、以下のような書き方もできます。

//書式指定文字列を指定して書き込み
int kazu = 10;
fprintf(fp, "%d", kazu);

ちなみにfprintf関数の第一引数にstdoutを指定すると、printf関数と全く同じとなります。

//標準出力(画面)に文字列を表示
fprintf(stdout, "あいうえお");

書き込みが終わったら、ファイル読み込みの場合と同じようにfclose関数でファイルをクローズして、プログラムは終了します。

printf関数に関して詳しくはprintf関数を参照してください。

fputs関数

ファイルへの書き込み関数にはfprintf関数のほかに、fputs関数というのもあります。
ファイルの読み取りにはfgets関数を使用しましたが、これと対になる関数です。

int fputs(
 const char *str,
 FILE *stream
);
文字列strをファイルストリームstreamに出力する。
戻り値は0以上の値。
関数が失敗した場合はEOFを返す。
#include <stdio.h>
#include <string.h>

#define BUFFER 256

int main()
{
    printf("保存する文字列を入力してください\n");

    char output[BUFFER];
    fgets(output, BUFFER, stdin);
    if (output[strlen(output) - 1] != '\n')
        while (getchar() != '\n');

    FILE *fp;
    const char *file = "C:\\test.txt";

    //fp = fopen(file, "w");
    fopen_s(&fp, file, "w");

    if (fp == NULL)
    {
        printf("%sのオープンに失敗しました。\n", file);
        printf("Enterキーで終了。\n");
        getchar();
        return 0;
    }

    fputs(output, fp);

    fclose(fp);

    printf("%sに保存しました\n", file);
    getchar();
}

29行目をfprintf関数からfputs関数に変更しただけです。

fputs関数とfprintf関数はどちらを使用しても構いませんが、fputs関数で書き込めるのは文字列のみです。
fprintf関数で書き込まれるのも文字列ですが、変換指定子により整数値などもそのまま文字列に変換して書き込みができます。

FILE *fp;

//ファイルオープン等の処理
//...

char *str = "ABCDEFG";
int integer = 10;
double real = 3.141526535897;

//fprintfを使用して書き込み
fprintf(fp, "%s\n%d\n%.12f", str, integer, real);

//fputsを使用して書き込み
char output[30];
sprintf_s(output, 30, "%s\n%d\n%.12f", str, integer, real);
fputs(output, fp);

文字列を成形して書き込みたい場合や、数値を文字列として書き込みたい場合にはfprintf関数を使った方が便利です。
(itoa関数の使用はあまり推奨されず、結局sprintf関数で同じようなことをするので少し手間が増えます)

EOF

fputs関数の戻り値であるEOFとは、ファイルの終端を表す定数です。
(End Of Fileの略)

ファイルを読み書きする関数では、ファイルの終端に達した場合や、何らかのエラーが発生した時にEOFを返すようになっている関数が多いです。
ただし、エラーの発生時はNULLやその他の値を返す関数もあるので、混同しないように注意しましょう。