ファイルを開いて閉じる
fopenは成功するとFILE *、失敗するとNULLを返します。使い終わったらfcloseし、その結果も確認します。
| モード | 動作 |
|---|---|
r | 読み取り。存在しなければ失敗 |
w | 書き込み。既存内容を消す |
a | 末尾へ追記 |
rbなど | バイナリモード |
テキストを書く
scores.txtを作るC
#include <stdio.h>
int main(void) {
FILE *file = fopen("scores.txt", "w");
if (file == NULL) { perror("scores.txt"); return 1; }
if (fprintf(file, "Aki,82\nMika,91\n") < 0) {
perror("書き込み"); fclose(file); return 1;
}
if (fclose(file) == EOF) { perror("閉じる"); return 1; }
printf("保存しました\n");
return 0;
}実行結果OUTPUT
保存しましたscores.txtTEXT
Aki,82
Mika,91一行ずつ読み込む
fgetsは配列サイズを指定できるため、一行を安全に読みやすい関数です。
内容を表示C
#include <stdio.h>
int main(void) {
FILE *file = fopen("scores.txt", "r");
if (file == NULL) { perror("scores.txt"); return 1; }
char line[128];
while (fgets(line, sizeof line, file) != NULL) fputs(line, stdout);
if (ferror(file)) { perror("読み取り"); fclose(file); return 1; }
fclose(file);
return 0;
}実行結果OUTPUT
Aki,82
Mika,91読み取った値を変換する
簡単な形式ならsscanfで変換数を確認できます。ただし、この例は名前にカンマが含まれない独自形式であり、一般的なCSVを完全には扱いません。次のコードは、前の例でfgetsにより一行をlineへ読み込んだあとの、main関数内へ記述する部分です。
main関数内の解析部分C
char name[32];
int score;
if (sscanf(line, "%31[^,],%d", name, &score) == 2) {
printf("%s: %d点\n", name, score);
} else {
fprintf(stderr, "形式が正しくありません: %s", line);
}Aki,82を解析すると「Aki: 82点」と表示されます。幅31は配列末尾のヌル文字分を残します。
バイナリデータを扱う
fwriteとfreadは指定したサイズと個数でデータを扱います。次のコードはstdio.hを読み込んだプログラムの、main関数内へ記述する部分です。
main関数内の保存部分C
int values[] = {10, 20, 30};
FILE *file = fopen("values.bin", "wb");
if (file == NULL) return 1;
size_t written = fwrite(values, sizeof values[0], 3, file);
if (written != 3) { fclose(file); return 1; }
fclose(file);互換性 構造体や整数をそのまま保存した形式は、型サイズ、バイト順、パディングの違いで別環境から読めないことがあります。交換用データには形式を明確に定義します。
安全なファイル操作
確認すること
- 利用者入力を検証せずパスへ使わない
wは既存内容を消すため、重要ファイルを直接上書きしない- 読み書き件数と
ferrorを確認する - 秘密情報を公開フォルダーへ保存しない
- 文字コードと改行コードを利用側と揃える
ミニ課題:学習記録
日付、学習内容、分数を一行ずつファイルへ追記し、全行を読み込んで合計時間を表示してください。不正な行は行番号とともに報告します。
