ファイル入出力
ファイル操作
これまでの知識では、外部のデータを読み書きすることが不可能だった。つまり、プログラムの終了時に内部データが失われてしまうため、ランキングやハイスコアを実装できない。また、マップデータや敵のパラメータなどをソースファイル内に記述すると、調整のたびにいちいちコンパイルを通さなければならず、非常に面倒である。
ファイル操作を学ぶことで、これらの問題点を解消できる。ぜひ覚えよう。
ファイルを扱うためには、まず、FILE型へのポインタを用意し、fopen()でファイルを紐付けする。すると、プログラム中でそのファイルを触ることが可能になる。
また、開いたファイルはfclose()で明示的に閉じる必要がある。
#include <stdio.h>
int main()
{
const char* filename = "noclose.txt";
FILE* fp;
for (int i = 0; i < 600; ++i)
{
fp = fopen(filename, "w");
printf("%d\n", fp->_file);
//fclose(fp); //閉じ忘れると……?
}
return 0;
}
ファイルを開くとき、モードを指定する必要がある。以下の文字列を第2引数に指定する。
- "r" テキスト読み取り
- "w" テキスト生成(上書き)
- "a" テキスト追加(終端から書き込み)
- "rb" バイナリ読み取り
- "wb" バイナリ生成(上書き)
- "ab" バイナリ追加(終端から書き込み)
- "r+" テキスト更新
- "w+" テキスト生成/読み取り(上書き)
- "a+" テキスト更新(終端から書き込み)
- "r+b"/"rb+" バイナリ更新
- "w+b"/"wb+" バイナリ生成/読み取り(上書き)
- "a+b"/"ab+" バイナリ更新(終端から書き込み)
テキストとバイナリ
テキストとは、文字列でデータを保持するファイル形式である。int型の変数のサイズは桁数*sizeof(char)である。
バイナリとは、ビット列でデータを保持するファイル形式である。int型の変数のサイズはsizeof(int)である。
実際に使う上では、以下の様な特徴があるだろう。
テキスト
- テキストエディタがあれば編集が可能で、直感的。
- プログラム中で文字列←→データに相互移動する必要がある。
バイナリ
- エディタを作らなければ編集が大変。
- プログラム中では、データを直接読み書きできる。
テキスト形式
テキストファイルについては、これまで扱ってきたprintf、scanfなどに対応するような関数が存在する。
printf(文字列, ...)→fprintf(ファイルポインタ, 文字列, ...)
scanf(文字列, ...)→fscanf(ファイルポインタ, 文字列, ...)
getchar()→fgetc(ファイルポインタ)
rewind(ファイルポインタ):ファイルポインタをファイルの先頭まで巻き戻す
//前回実行時の文字列を表示するプログラム
#include <stdio.h>
int main()
{
char str[256];
const char* filename = "text.txt";
FILE* fp = fopen(filename, "r");
if (fp == NULL)
{
printf("前回実行時の結果はありません\n");
}
else
{
fscanf(fp, "%255s", str);
fclose(fp);
printf("前回実行時:\n%s\n", str);
}
printf("文字列を入力してください\n");
scanf("%255s", str);
fp = fopen(filename, "w");
fprintf(fp, "%s", str);
fclose(fp);
return 0;
}
バイナリ形式
バイナリファイルは、fwrite、freadで読み書きできる。
fwrite(ポインタ、サイズ、要素数、ファイルポインタ)
fread(ポインタ、サイズ、要素数、ファイルポインタ)
第1引数がポインタであることから分かるように、配列を読み書きしやすいよう設計されている。
//2,3,5の平方根を表示するプログラム
#include <stdio.h>
#include <math.h>
int main()
{
const char* filename = "bin.b";
double arr[3] = { sqrt(2.0), sqrt(3.0), sqrt(5.0) };
FILE* fp;
fp = fopen(filename, "rb");
if (fp != NULL)
{
fread(arr, sizeof(double), 3, fp);
fclose(fp);
for (int i = 0; i < 3; ++i)
{
printf("%.16d\n", arr[i]);
}
}
else
{
fp = fopen(filename, "wb");
fwrite(arr, sizeof(double), 3, fp);
fclose(fp);
}
return 0;
}
課題
- 5位まで保存できるランキングを実装せよ。データの構造体を以下に示す。
- scanfで構造体にデータを渡し、ソートして保存する。
- ファイルからデータを読み込み、出力する。
- 保存形式は問わない。
typedef struct
{
char name[64];
int score;
}rankdata;
最終課題
ゲームを制作せよ。