序文
前回の記事ではファイル操作に関連する機能について学習しましたが、今回はバイナリ ファイルとファイル バッファーについての知識を学習します。
1. テキストファイルとバイナリファイル
データの編成方法に応じて、データ ファイルはテキスト ファイルまたはバイナリ ファイル<と呼ばれます。 /span> a>。
- データはバイナリ形式でメモリに保存されており、そのまま外部メモリに出力するとバイナリファイルとなります。
- 外部ストレージに ASCII コードで保存する必要がある場合は、保存前に変換する必要があります。 ASCII 文字の形式で保存されたファイルはテキスト ファイルです。
データはどのようにメモリに保存されるのでしょうか?
- 文字は常に ASCII 形式で保存され、数値データは ASCII 形式またはバイナリ形式で保存できます。
- たとえば、整数 10000 がある場合、ASCII コード形式でディスクに出力すると、ディスク上で 5 バイト (1 文字につき 1 バイト) を占有しますが、バイナリ形式で出力すると、ディスク上で 5 バイトを占有します。ディスク上で占有するのは 4 バイトのみです (VS2013 テスト)。
#include <stdio.h> int main() { int a = 10000; FILE* pf = fopen("test.txt", "wb"); fwrite(&a, 4, 1, pf);//二进制的形式写到文件中 fclose(pf); pf = NULL; return 0; }
このコードを実行後、「test.txt」文書をテキストモードで開くと文字化けが表示されますが、バイナリモードで開くと正常に表示されます。
2. ファイル読み込み完了の判定
2.1 feofの悪用
注意: ファイル読み取りプロセス中、feof 関数の戻り値を使用してファイルが終了したかどうかを直接判断することはできません。
代わりに、ファイルの読み取りが終了したときに、読み取りが失敗したか、ファイルの終わりに達したかを判断するために使用されます。
1. テキスト ファイルの読み込みが完了したかどうかを確認し、戻り値が EOF (fgetc) か NULL (fgets) かを判断します。
例: あ>
- fgetc は EOF かどうかを判断します。
- fgets は戻り値が NULL かどうかを判断します。
2. バイナリファイルの読み込み終了の判定、戻り値が実際に読み込む数値より小さいかどうかを判定します。
例:
- fread は、戻り値が実際に読み取られる数値より小さいかどうかを判断します。
正しい使用法:
テキスト ファイルの例:#include <stdio.h> #include <stdlib.h> int main(void) { int c; // 注意:int,非char,要求处理EOF FILE* fp = fopen("test.txt", "r"); if (!fp) { perror("File opening failed"); return EXIT_FAILURE; } //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环 { putchar(c); } //判断是什么原因结束的 if (ferror(fp)) puts("I/O error when reading"); else if (feof(fp)) puts("End of file reached successfully"); fclose(fp); }
注:1.ferror -- ファイルの読み取り後、ファイルの読み取りプロセス中にエラーが発生したかどうかを判断するために使用されます。 そして終了。
2.feof -- ファイルが読み取られた後、ファイルが読み取り中かどうかを判断するために使用されますファイルの終わりフラグが検出されました そして終了。
バイナリ ファイルの例:
#include <stdio.h> enum { SIZE = 5 }; int main(void) { double a[SIZE] = { 1.,2.,3.,4.,5. }; FILE* fp = fopen("test.bin", "wb"); // 必须用二进制模式 fwrite(a, sizeof * a, SIZE, fp); // 写 double 的数组 fclose(fp); double b[SIZE]; fp = fopen("test.bin", "rb"); size_t ret_code = fread(b, sizeof * b, SIZE, fp); // 读 double 的数组 if (ret_code == SIZE) { puts("Array read successfully, contents: "); for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]); putchar('\n'); } else { // error handling if (feof(fp)) printf("Error reading test.bin: unexpected end of file\n"); else if (ferror(fp)) { perror("Error reading test.bin"); } } fclose(fp); }
コードが (if (ret_code == SIZE)) に達すると、読み取り操作中に多くのバイトのデータが正常に読み取れたかどうかが判断され、読み取れた場合は出力されます。そうでない場合は、feof とferror. 、読み取りの終了を引き起こした発生したエラー。
3. ファイルバッファ
Ansic 標準は「 クッション ファイル システム いわゆるバッファ ファイル システムを指します。プログラムで使用されている各ファイルは、" ファイル バッファ」。メモリからディスクに出力されたデータは、まずメモリ内のバッファに送られ、バッファがいっぱいになった後にまとめてディスクに送られます。ディスクからコンピュータにデータを読み取る場合、データはディスク ファイルから読み取られてメモリ バッファに入力され (バッファがいっぱいになります)、その後データがバッファからプログラム データ領域 (プログラム変数、など)一つ一つ。バッファのサイズは C コンパイル システムによって決定されます。
データがハードディスクに直接配置されず、バッファを介して配置されるのはなぜですか? fputc や fwrite などの関数を使用するときは、システム インターフェイスを呼び出す必要があります。頻繁に呼び出すと、システムはこの 1 つのプログラムだけを処理するわけではないため、オペレーティング システムの効率が低下します。メモリをディスクに転送する場合、最初にメモリに送信され、バッファがいっぱいになってから一緒にディスクに送信されます。これにより、オペレーティング システムの効率が大幅に向上します。
バッファの存在を証明します。
#include <stdio.h> #include <windows.h> //VS2022 WIN11环境测试 int main() { FILE* pf = fopen("test.txt", "w"); fputs("abcdef", pf);//先将代码放在输出缓冲区 printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n"); Sleep(10000); printf("刷新缓冲区\n"); fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘) //注:fflush 在高版本的VS上不能使用了 printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n"); Sleep(10000); fclose(pf); //注:fclose在关闭文件的时候,也会刷新缓冲区 pf = NULL; return 0; }
10 秒間スリープします - データは書き込まれています。test.txt ファイルを開くと、ファイルに内容がないことがわかります。
さらに 10 秒間スリープします。この時点で、test.txt ファイルを再度開くと、ファイルにコンテンツが含まれます。
ここで結論を導き出すことができます: バッファが存在するため、C 言語はファイルを開くときはファイル操作の最後にバッファを更新するか、ファイルを閉じる必要があります。そうしないと、ファイルの読み取りおよび書き込みで問題が発生する可能性があります。