HOWTO · C
C 言語で fscanf を使ってファイルを一行ずつ読む
この記事では、C 言語で fscanf を使ってファイルを一行ずつ読み込む方法を説明します。
このページの内容
fscanf は FILE ストリームから書式付き入力を読み取ります。スキャンセットを使うと改行までの文字を集められますが、専用の行読み込み関数とは異なり、空行やバッファに収まる長さのデータを明示的に扱う必要があります。一般的なテキストファイルでは fgets のほうが通常は簡単です。入力形式に応じた変換が必要な場合は fscanf を使います。
Cでfscanfを使ってファイルを1行ずつ読み取る
次の完全な例では、一時ファイルを作成してサンプルの2行を書き込み、格納先バッファのサイズである16バイトに収まるようスキャンセットでストリームを読み取ります。プログラムは一時ストリームに書き込んだ2行を、読み取りながら出力します。
#include <stdio.h>
int main(void) {
FILE *file = tmpfile();
char line[16];
if (file == NULL) {
return 1;
}
if (fputs("First line.\nSecond line.\n", file) == EOF || ferror(file)) {
fclose(file);
return 1;
}
if (fflush(file) == EOF || ferror(file)) {
fclose(file);
return 1;
}
rewind(file);
for (;;) {
int result = fscanf(file, "%15[^\n]", line);
if (result == 1) {
int ch;
puts(line);
ch = fgetc(file);
if (ch == '\n') {
continue;
}
if (ch == EOF) {
break;
}
ungetc(ch, file);
while ((ch = fgetc(file)) != '\n' && ch != EOF) {
}
if (ch == EOF) {
break;
}
continue;
}
if (result == EOF) {
break;
}
if (fgetc(file) == '\n') {
puts("");
}
}
fclose(file);
return 0;
}
幅を15にすると、line の末尾に終端ヌル文字を格納する余地が残ります。スキャンセットによる変換に成功するたび、プログラムは改行文字を確認します。行がバッファより長い場合は、次の行を読む前に残りを破棄します。これによりメモリ使用量を一定に保てますが、長い行全体は保存されません。改行位置でスキャンセットに一致する文字がない場合、ループは改行を読み飛ばして空行を出力するため、進まないまま再試行することはありません。本番コードでは、入力終了後に ferror(file) も確認し、読み取りエラーと通常のファイル終端を区別してください。
fscanfで空白区切りのトークンを読み取る
トークンを解析する場合、%255s は空白以外の文字からなるトークンを1つ、char token[256] バッファに読み取ります。幅を指定しているため配列の範囲を超えて書き込まず、%s は先頭の空白を読み飛ばし、次の空白文字で読み取りを止めます。ループは fscanf(file, "%255s", token) == 1 の間だけ続けてください。EOF だけを確認すると、入力を消費しない変換失敗が起きたときにループが終わらず、繰り返し続けることがあります。この方法ではスペース、タブ、改行を区切りとして扱うため、元の行の境界は保持されません。数値フィールドには対応する変換指定子を使い、代入に成功した数も確認してください。
行単位で確実に読み取るには fgets を使う
各レコードが1行であるテキストでは、fgets(buffer, sizeof buffer, file) のほうが一般に動作を把握しやすくなります。バッファ容量より最大1文字少ない長さまで読み取り、収まる場合は改行も保持します。バッファを使う前に、戻り値を確認してください。改行が入る前にバッファがいっぱいになった場合、論理上の行はストリーム内で続いています。用途に応じて、さらに読み取るか、残りを破棄してください。最後の行には改行がない場合があります。空行も自然に扱え、改行だけを含むバッファが返ることがあります。
書式付きフィールドや空白区切りのトークンが必要なら fscanf を使います。行の境界を保持したい場合は fgets を使い、必要に応じて読み取った文字列を別途解析してください。fopen の成功、変換結果を必ず確認し、使用後はストリームを閉じてください。