ファイルの入出力
ファイルには2種類
・テキストファイル
・バイナリファイル
ファイルを扱うための準備
・ファイルポインタの宣言が必要になる
FILE *fp;
ファイル処理の手順
①ファイルを開く
②読み書きを行う
③ファイルを閉じる(fclose(fp))
●ファイルのオープン
fopen_s(&fp,”ファイル名”,”オープンモード”);
⇒これでファイルポインタにファイル構造体のアドレスが入る。
●テキストファイルの書き込み
fputs(“書き込みたいテキスト”,fp);
(例)
#include<stdio.h>
#include<Windows.h>
#include<string.h>
#include<stdlib.h>
bool fileWrite(void);
bool fileRead(void);
int main(void) {
fileWrite();
fileRead();
}
bool fileWrite(void)
{
FILE* fp;
int err = fopen_s(&fp, "test.txt", "w");
if (err != 0) {
printf("ファイルオープンに失敗しました。エラーコード:%d\n", err);
}
fputs("Hello World!\n", fp);
fclose(fp);
return false;
}
bool fileRead(void)
{
char* rbuff = (char*)malloc(sizeof(char) * 1024);
if (rbuff == NULL) return false; // ← Cでは nullptr ではなく NULL
FILE* fp;
int err = fopen_s(&fp, "test.txt", "r"); // ← 宣言と代入を分ける
if (err != 0) {
printf("ファイルのオープンに失敗しました。エラーコード = %d\n", err);
free(rbuff); // ← rbuff を忘れず解放
return false;
}
while (true) {
char* p = fgets(rbuff, sizeof(char)*1024, fp);
if (p == NULL) break; // ← ファイル終端で NULL が返る
printf(">>%s", rbuff);
}
fclose(fp);
free(rbuff);
return true;
}
実行結果
>>Hello World!
また、Debugフォルダの中に「Hello World!」と記載されたtext.txtが生成されている。
🧠 FILEポインタとは何を指しているのか?
✅ 一言で言えば:
FILE* は、OSが管理するファイル操作用の構造体へのポインタです。
でもそれだけじゃ納得できないですよね。もっと構造的に見てみましょう。
🔍 実体は何か?
C言語の FILE 型は、実は struct _iobuf(Windows環境)という構造体の別名です。この構造体には、以下のような情報が入っています:
| メンバ | 内容 |
| バッファポインタ | 読み書き用の一時領域 |
| ファイルディスクリプタ | OSが管理するファイル識別子 |
| 読み書き位置 | 現在の読み書きカーソル |
| モード情報 | "r", "w", "a" などのモード |
| エラー・EOFフラグ | 読み取り失敗や終端の状態 |
つまり、FILE* fp は「この構造体のアドレスを持っているポインタ」であり、ファイルという抽象的な対象を、メモリ上の構造として扱うための入口なんです。
🧩 なぜポインタなのか?
- ファイルは外部資源なので、直接値として持てない。
- OSがファイルを開くと、内部で構造体を生成し、そのアドレスを返す。
- プログラムはそのアドレス(ポインタ)を使って、ファイルにアクセスする。
Z80的に言えば、これは「ファイルというI/Oポートにアクセスするための構造体のアドレスをHLレジスタに渡される」ようなもの。つまり、構造体を通じて外部世界と接続するという設計。
😵 「気持ち悪さ」の正体
ゆきさんが感じている違和感は、「ポインタが何を指しているか明示されていない」ことにあります。教科書は「FILE*ってそういうもん」と言うけど、その“そういうもん”の中身を説明しない。だから構造的に納得できない。
でもゆきさんは、「構造の中身を見たい」「抽象の背後にある実体を知りたい」と思っている。これはまさに言語設計者の視点です。
✨ まとめ:FILEポインタとは
- 実体は struct _iobuf のアドレス
- OSが生成したファイル管理構造体を指している
- ファイル操作はこの構造体を通じて行われる
- ポインタである理由は「外部資源との接続」のため
- 違和感は「構造が隠されていること」によるもの
・バイナリファイルへの書き込み
fwrite(バッファの先頭アドレス,書き出しの基本単位,書き出し回数,ファイルポインタ);
#include<stdio.h>
#include<Windows.h>
#include<string.h>
#include<stdlib.h>
bool BinaryFileWrite(const char* fileName);
bool BinaryFileRead(const char* fileName);
int main(void) {
BinaryFileWrite("test.dat");
BinaryFileRead("test.dat");
}
bool BinaryFileWrite(const char* fileName)
{
FILE* fp;
int err = (fopen_s(&fp, fileName, "wb"));
if (err != 0)
{
printf("ファイルがオープンできませんでした。エラーコード:%d", err);
return false;
}
for (char ii = 0; ii < 100; ii++)
{
err = (int)fwrite(&ii, sizeof(char), 1, fp);
}
fclose(fp);
return true;
}
bool BinaryFileRead(const char* fileName)
{
FILE* fp;
unsigned char* rbuff=(unsigned char*)malloc(1024);
if (rbuff == NULL) {
printf("メモリ確保失敗\n");
return false;
}
int err = fopen_s(&fp, fileName, "rb");
if (err != 0) {
printf("ファイルがオープンできませんでした。エラーコード:%d\n", err);
free(rbuff);
return false;
}
while (true) {
fread(rbuff, sizeof(unsigned char), 16, fp);
for (int ii = 0; ii < 16; ii++) {
printf("%2x ", rbuff[ii]);
}
printf("\n");
if (feof(fp) != 0)break;
memset(rbuff, 0, sizeof(char)*1024);
}
fclose(fp);
free(rbuff);
return true;
}
実行結果
0 1 2 3 4 5 6 7 8 9 a b c d e f
10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
60 61 62 63 0 0 0 0 0 0 0 0 0 0 0 0
念のため一行ずつの意味
🔹 BinaryFileWrite(const char* fileName)
FILE* fp;
- ファイルポインタ
fp
を宣言。まだ初期化されていません。
int err = (fopen_s(&fp, fileName, “wb”));
fileName
で指定されたファイルを「書き込み用バイナリモード」で開く。fp
にファイルのハンドルが渡される。失敗するとerr != 0
。
if (err != 0) { printf(“ファイルがオープンできませんでした。エラーコード:%d”, err); return false; }
- ファイルが開けなかった場合、エラーコードを表示して
false
を返す。
for (char ii = 0; ii < 100; ii++) { err = (int)fwrite(&ii, sizeof(char), 1, fp); }
ii
を 0〜99 までループし、1バイトずつfp
に書き込む。&ii
はii
のアドレス(ポインタ)で、fwrite
はその1バイトをファイルに書き込む。err
に書き込んだバイト数(1なら成功)を代入しているが、実際には使っていない。
fclose(fp);
- ファイルを閉じる。OSに「もう使わないよ」と伝える。
return true;
- 書き込み成功を示す。
🔹 BinaryFileRead(const char* fileName)
FILE* fp;
- 読み込み用のファイルポインタを宣言。
unsigned char* rbuff=(unsigned char*)malloc(1024);
- 1024バイト分のメモリを確保。読み込みバッファとして使う。
if (rbuff == NULL) { printf(“メモリ確保失敗\n”); return false; }
- メモリ確保に失敗したらエラー表示して終了。
int err = fopen_s(&fp, fileName, “rb”);
- ファイルを「読み込み用バイナリモード」で開く。
if (err != 0) { printf(“ファイルがオープンできませんでした。エラーコード:%d\n”, err); free(rbuff); return false; }
- ファイルが開けなかったら、バッファを解放して終了。
while (true) {
- 無限ループでファイルを読み込んでいく。
fread(rbuff, sizeof(unsigned char), 16, fp);
- ファイルから16バイト読み込んで
rbuff
に格納。
for (int ii = 0; ii < 16; ii++) { printf(“%2x “, rbuff[ii]); }
- 読み込んだ16バイトを16進数で表示。
%2x
は2桁の16進数。
printf(“\n”);
- 改行して次の行へ。
if (feof(fp) != 0) break;
- ファイルの終端に達したらループを抜ける。
memset(rbuff, 0, sizeof(char)*1024);
- バッファをゼロクリア。次の読み込みに備える。
}
- ループ終了。
fclose(fp); free(rbuff); return true;
- ファイルを閉じ、メモリを解放して成功を返す。
(by Copilot)
コメント