<C言語> ファイル操作

1 ファイルポインタ

キャッシュ ファイル システムでは、重要な概念は「ファイル タイプ ポインター」であり、「ファイル ポインター」と呼ばれます

使用された各ファイルは、メモリ内の対応するファイル情報領域を開き、ファイルの関連情報 (ファイル名、ファイルのステータス、ファイルの現在の場所など) を保存するために使用されます。 )。この情報は構造体変数に保存されます。構造体の型はシステムによって宣言され、 という名前が付けられますFILE

たとえば、VS2013 コンパイル環境によって提供されるヘッダー ファイルにはstdio.h次のファイル タイプ宣言があります。

struct _iobuf{
    
    
    char *_ptr;
    int _cnt;
    char *_base;
    int _flag;
    int _file;
    int _charbuf;
    int _bufsiz;
    char *_tmpfname;
};
typedef struct _iobuf FILE;

異なる C コンパイラの FILE タイプの内容はまったく同じではありませんが、似ています。

ファイルを開くたびに、システムがファイルの状況に応じてFILE構造の変数を自動的に作成し、情報を埋めていくため、ユーザーは詳細を気にする必要がありません。

一般に、この FILE 構造体の変数は FILE ポインタを通じて維持されるため、使用するのがより便利です。

以下では、FILE* ポインター変数を作成できます。

FILE* pf;   //文件指针变量

pf を FILE 型データを指すポインタ変数として定義します。pf に特定のファイルのファイル情報領域を指すようにすることができます(構造体変数です)。ファイル情報領域の情報を介してファイルにアクセスできます。つまり、それに関連付けられたファイルは、ファイル ポインタ変数を通じて見つけることができます

2 ファイルのオープンとクローズ

ファイルは読み取りおよび書き込みの前に開き、使用後に閉じる必要があります。

プログラムを作成するとき、ファイルを開くとき、ファイルを指す FILE* ポインター変数が返されます。これは、ポインターとファイルの間の関係を確立することと同じです。

fopen機能: ファイルを開くために使用されます。

関数プロトタイプ:

FILE *fopen(const char *filename, const char *mode);
  • filename引数は開くファイルの名前で、相対パスまたは絶対パスを指定できます。
  • modeこのパラメータは、次のオプションを使用して、ファイルを開くモードを指定します。
オープンメソッド 説明 ファイルが存在しない場合
「r」 既存のテキスト ファイルを読み取り専用モードで開きます。 オープンに失敗し、NULL ポインタが返されます。
「わ」 書き込みモード。ファイルが存在する場合はファイルを 0 バイトに切り捨て、存在しない場合は新しいファイルを作成します。 新しい空のファイルを作成します。
「あ」 追加モード。ファイルの末尾にデータを追加するか、ファイルが存在しない場合は新しいファイルを作成するために使用されます。 新しい空のファイルを作成します。
「rb」 ファイルをバイナリ読み取り専用モードで開きます オープンに失敗し、NULL ポインタが返されます。
「わー」 ファイルをバイナリ書き込みモードで開き、ファイルが存在する場合はファイルを 0 バイトに切り詰め、存在しない場合は新しいファイルを作成します。 新しい空のファイルを作成します。
「アブ」 ファイルをバイナリ追加モードで開くか、ファイルが存在しない場合は新しいファイルを作成します。 新しい空のファイルを作成します。
「r+」 読み取り/書き込みモードでは、既存のテキスト ファイルが開き、読み取りと書き込みが可能になります。 オープンに失敗し、NULL ポインタが返されます。
「w+」 読み取り/書き込みモードでは、ファイルが存在する場合はファイルが 0 バイトに切り詰められ、ファイルが存在しない場合は新しいファイルが作成され、読み取りと書き込みが可能になります。 新しい空のファイルを作成します。
「a+」 ファイルの末尾にデータを追加するための読み取り/書き込みモード。ファイルが存在しない場合は新しいファイルを作成し、読み取りと書き込みを可能にします。 新しい空のファイルを作成します。
「r+b」 読み取り/書き込みモードでは、既存のファイルをバイナリ モードで開き、読み取りと書き込みを可能にします。 オープンに失敗し、NULL ポインタが返されます。
「w+b」 読み取り/書き込みモード。バイナリ モードでファイルを開き、ファイルが存在する場合はファイルを 0 バイトに切り捨て、ファイルが存在しない場合は新しいファイルを作成し、読み取りと書き込みを許可します。 新しい空のファイルを作成します。
「a+b」 読み取り/書き込みモード。バイナリでファイルの末尾にデータを追加し、ファイルが存在しない場合は新しいファイルを作成し、読み取りと書き込みを許可します。 新しい空のファイルを作成します。

fclose機能: ファイルを閉じるために使用されます。

関数プロトタイプ:

int fclose(FILE *stream);
  • stream引数は、閉じるファイルを識別するfopen関数によって返される型へのポインタです。FILE

例:

#include <stdio.h>
int main() {
    
    
    FILE *pf1 = fopen("HelloWorld.text", "w"); //打开失败返回空指针   在工程下创建文件(相对路径)
    FILE *pf2 = fopen("c:\\code\\1.text", "w");//打开失败返回空指针  在C盘创建文件(绝对路径)

    if (pf1 == NULL) {
    
    
        perror("fopen pf1");
        return 1;
    }

    if (pf2 == NULL) {
    
    
        perror("fopen pf2");
        return 1;
    }

    //关闭文件
    fclose(pf1);
    fclose(pf2);
    pf1 = NULL;
    pf2 = NULL;
    return 0;
}
// 输出结果:fopen pf2: No such file or directory    C盘没有该目录

ここに画像の説明を挿入

3. ファイルのシーケンシャル読み取りと書き込み

3.1 fgetc と fputc

fgetcfputcファイルの読み取りと書き込みのための標準ライブラリ関数これらは、ファイルから 1 文字を読み取り、ファイルに 1 文字を書き込むために使用されます。

fgetc関数:

int fgetc(FILE *stream);

fgetc指定されたファイル ストリーム (FILEポインターで表される) からstream文字を読み取る関数。読み取った文字を返します。ファイルの終わりを読み込んだ場合、またはエラーが発生した場合は、EOF(End of File) を返します。

使用例:

#include <stdio.h>
int main() {
    
    
    //打开文件
    FILE *pf = fopen("text.text", "w");

    if (pf == NULL) {
    
    
        perror("fopen");
        return 1;
    }

    //写文件
    int i = 0;
    for (i = 0; i < 26; i++) {
    
    
        fputc('a' + i, pf);
    }

    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

ここに画像の説明を挿入

fputc関数:

int fputc(int character, FILE *stream);

fputcFILE指定されたファイル ストリーム (ポインターで表される) に文字を書き込む関数stream書き込まれた文字、または書き込み中にエラーがあった場合はその文字を返しますEOF

使用例:

#include <stdio.h>
int main() {
    
    
    //打开文件
    FILE *pf = fopen("text.text", "r");

    if (pf == NULL) {
    
    
        perror("fopen");
        return 1;
    }

    //读文件
    int ch = 0;
    while ((ch = fgetc(pf)) != EOF) {
    
    
        printf("%c", ch);
    }
    //每次读取后 pf指针会自动加1

    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

ここに画像の説明を挿入

fgetcおよび は低レベルのファイル I/O 関数です。C 言語には、文字列やテキスト行の読み書きに便利な、や などfputcのより高度なファイル読み取りおよび書き込み関数も用意されています。fgetsfputs

3.2 fget と fput

fgetsと はファイルの読み取りと書き込みのための標準ライブラリ関数であり、文字列やテキスト行の読み取りと書き込みにfputsは と よりも便利ですfgetcfputc

fgets関数:

char *fgets(char *str, int n, FILE *stream);

fgetsFILE指定されたファイル ストリーム (ポインタで表される) からテキスト行を読み取りstream、それを文字配列に格納する関数strこのパラメータは、nバッファ オーバーフローを避けるために読み取る最大文字数 (改行とターミネータを含む) を指定します。読み取られたテキストには改行が含まれ (存在する場合)、\0ヌル文字で終了します。

使用例:

#include <stdio.h>
int main() {
    
    
    //打开文件
    FILE *pf = fopen("text.text", "w");

    if (pf == NULL) {
    
    
        perror("fopen");
        return 1;
    }

    //写文件
    fputs("hello ", pf);
    fputs("World", pf);
    //如果文件本身有内容 就会清楚原来文件的所有内容  在写入

    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

ここに画像の説明を挿入

fputs関数:

int fputs(const char *str, FILE *stream);

fputs指定されたファイル ストリーム (ポインターで表される)に null で\0終了する文字列を書き込む関数。文字列の末尾に余分な改行は追加されないため、手動で追加する必要があります。strFILEstream

使用例:

#include <stdio.h>
int main() {
    
    
    //打开文件
    FILE *pf = fopen("text.text", "r");

    if (pf == NULL) {
    
    
        perror("fopen");
        return 1;
    }

    //读文件一行一行读   只读一行
    char arr[20] = "#########";
    fgets(arr, 20, pf);
    printf("%s", arr);
    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

ここに画像の説明を挿入

前のfgetcと と同様にfputcfgetsfputsもエラー チェックを実行し、ファイル ポインタが不要になったらファイルを閉じる必要があります。これらは、テキスト ファイルやテキスト行の読み取りと書き込みにより適しており、テキスト行を簡単に読み取ったり、改行文字を含む文字列を書き込んだりできます。

3.3 fprintf と fscanf

fscanfおよび は、fprintfフォーマットされたファイルの入出力のための標準ライブラリ関数です。これらはscanf関数に似ていますprintfが、ファイルからデータを読み取ったり、ファイルにデータを書き込んだりできます。

fprintf関数:

int fprintf(FILE *stream, const char *format, ...);

fprintfこの関数は、指定されたフォーマット文字列に従って、フォーマットされたデータをformat指定されたファイル ストリーム (FILEポインターで表される) に書き込むために使用されます。引数は、関数の書式文字列と同様の書式文字列です。フォーマット文字列内のフォーマット指定子に従って、対応するデータが文字列に変換され、ファイルに書き込まれます。streamformatprintffprintf

例:

#include <stdio.h>
struct S {
    
    
    char name[20];
    int age;
    float score;
};

int main() {
    
    
    struct S s = {
    
    "zhangsan", 20, 95.5f};
    //把s中的结构体数据写到文件中
    FILE *pf = fopen("test.text", "w");
    if (pf == NULL) {
    
    
        perror("fopen");
        return 1;
    }
    //写文件
    fprintf(pf, "%s %d %f", s.name, s.age, s.score);
    return 0;
}

ここに画像の説明を挿入

fscanf関数:

int fscanf(FILE *stream, const char *format, ...);

fscanfこの関数は、指定されたファイル ストリーム ( FILEpointerで表される) からstream指定された形式文字列に従ってformatデータを読み取るために使用されます。読み取られたデータは書式文字列内の書式指定子に従って解析され、解析された値は対応する変数に格納されます。format引数は、scanf関数の書式文字列と同様の書式文字列です。

使用例:

#include <stdio.h>
struct S {
    
    
    char name[20];
    int age;
    float score;
};

int main() {
    
    
    struct S s = {
    
    0};
    //把s中的结构体数据读出来
    FILE *pf = fopen("test.text", "r");
    if (pf == NULL) {
    
    
        perror("fopen");
        return 1;
    }
    //读文件
    fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
    printf("%s %d %f", s.name, s.age, s.score);
    return 0;
}

ここに画像の説明を挿入

前の関数と同様に、fscanfエラーfprintfチェックを実行し、ファイル ポインターが必要ない場合はファイルを閉じる必要があります。ファイル内のデータの読み取りと書き込みが容易になり、指定された形式でのデータの入出力が可能になります。

3.4 fwrite と fread

freadおよび は、fwriteバイナリ ファイルの読み取りと書き込みのための標準ライブラリ関数です。fgetsfputsfscanfなどの以前の関数とは異なりfprintf、これら 2 つの関数はテキスト データではなくバイナリ データを処理します。これらは通常、バイナリ ファイルまたはバイナリ データのブロックの読み取りと書き込みに使用されます。

fwrite関数:

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

fwriteこの関数は、指定されたファイル ストリーム (ポインターで表される)ptrが指すメモリ領域からデータを書き込みます。このパラメータは、データ項目ごとのバイト数と、書き込むデータ項目の数を表します。この関数は、正常に書き込まれたデータ項目の実際の数を返します。通常は、すべてのデータが正しく書き込まれたことを確認するためにこの数値と比較する必要があります。FILEstreamsizenmembnmemb

例:

#include <stdio.h>
struct S {
    
    
    char name[20];
    int age;
    float score;
};

int main() {
    
    
    struct S s = {
    
    "zhangsan", 20, 95.5f};
    //把s中的结构体数据写到文件中
    FILE *pf = fopen("test.text", "wb");
    if (pf == NULL) {
    
    
        perror("fopen");
        return 1;
    }
    //写文件
    fwrite(&s, sizeof(s), 1, pf);
    return 0;
}

ここに画像の説明を挿入

fread関数:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

freadこの関数は、指定されたファイル ストリーム (FILEポインタで表されるstream) からデータを読み取り、それをptrが指すメモリ領域に格納します。このパラメータは、sizeデータ項目ごとのバイト数と、nmemb読み取るデータ項目の数を表します。この関数は、正常に読み取られたデータ項目の実際の数を返します。通常は、nmembすべてのデータが正しく読み取られたことを確認するためにこの値と比較する必要があります。

例:

#include <stdio.h>
struct S {
    
    
    char name[20];
    int age;
    float score;
};

int main() {
    
    
    struct S s = {
    
    0};
    //把s中的结构体数据读到文件中
    FILE *pf = fopen("test.text", "rb");
    if (pf == NULL) {
    
    
        perror("fopen");
        return 1;
    }
    //读文件
    fread(&s, sizeof(s), 1, pf);
    printf("%s %d %f\n", s.name, s.age, s.score);
    return 0;
}

ここに画像の説明を挿入

freadおよび は、fwriteバイナリ データを直接操作する下位レベルのファイル I/O 関数です。これらを使用する場合は、異なるプラットフォームや環境での問題を回避するために、バイト順序とデータ ストレージ形式に注意する必要があります。複雑なデータ構造を扱う必要がある場合、またはより高度なシリアル化関数が必要な場合は、処理に特化したライブラリまたは関数を使用することをお勧めします。

どの C プログラムでも、実行中であればデフォルトで 3 つのストリームが開かれます。

stdin- 標準入力ストリーム - キーボード

stdout- 標準出力ストリーム - 画面

stderr- 標準エラーストリーム - 画面

それらのタイプは両方とも FILE* です

int main()
{
    
    
    int ch = fgetc(stdin);  //键盘输入d
    fputc(ch,stdout);  //d键盘输出d
    return 0;
}
//printf ==  fprintf( ,stdout)

4. 一連の関数 sprintf/sscanf を比較する

scanf: 特定の形式に従ってキーボードからデータを入力します

printf:データを一定のフォーマットに従って画面に印刷(出力)します。

標準入出力ストリーム用のフォーマットされた入出力ステートメント

fscanf: 特定の形式に従って入力ストリーム (ファイル/標準入力) からデータを入力します。

fprintf: 特定の形式に従ってデータを出力ストリーム (ファイル/標準出力) に出力します

すべての I/O ストリームに対するフォーマットされた I/O ステートメント

sscanf

int sscanf(const char *s,const char* format,...

特定の形式に従って文字列から書式設定されたデータを読み取ります

sprintf

int sprintf(char * str,const char* format,...)

フォーマットされたデータを特定のフォーマットに従って文字列に変換します

例:

#include <stdio.h>
struct S {
    
    
    char name[10];
    int age;
    float score;
};

int main() {
    
    
    char buf[100] = {
    
    0};
    struct S tmp = {
    
    0};

    struct S s = {
    
    "zhangsan", 20, 95.5f};
    //能否把这个结构体的数据转换成字符串
    //转换成 - zhangsan 20 95.5
    sprintf(buf, "%s %d %f", s.name, s.age, s.score);
    printf("%s\n", buf);

    //能否将buf中的字符串还原成一个结构体数据
    sscanf(buf, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score));
    printf("%s %d %f\n", tmp.name, tmp.age, tmp.score);//以结构体的形式打印
    return 0;
}

ここに画像の説明を挿入

5. ファイルのランダムな読み取りと書き込み

5.1 fseek

fseek()ファイル位置インジケーターをファイル内の特定の位置に移動できるようにします。この関数は、ファイルの先頭からではなく、ファイル内の特定の位置からデータの読み取りまたは書き込みを開始する場合に特に便利です。

fseek()関数のプロトタイプは次のとおりです。

int fseek(FILE *stream, long int offset, int origin);

パラメータ:

  • stream:操作対象のファイルを表すFILEオブジェクトへのポインタ。ファイルは、読み取りまたは書き込みなどの位置決めをサポートするモードで開かれている必要があります。
  • offset: 移動するファイル位置インジケーターのバイト数。正の値はインジケーターを前方に移動し、負の値はインジケーターを後方に移動します。通常long intタイプです。
  • origin: オフセットを適用する基準位置。次のいずれかの値を取ることができます。
    • SEEK_SET(0): オフセットはファイルの先頭からの相対値です。
    • SEEK_CUR(1): オフセットは、現在のファイル ポインターの位置を基準としています。
    • SEEK_END(2): オフセットはファイルの終わりからの相対値です。

戻り値:

  • 成功した場合はfseek()0 を返します。
  • エラーが発生した場合は、失敗を示すゼロ以外の値が返されます。

例:

#include <stdio.h>
int main()
{
    
    
    FILE *pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
    
    
        perror("fopen()");
        return 1;
    }
    //读文件 - 文件中存放abcdef
    int ch = fgetc(pf);
    printf("%c\n", ch);       // 输出:a  读完后文件指针往后+1 指向b

    fseek(pf, 2, SEEK_CUR); //从当前文件指针往后偏移2个  (当前是b)
    ch = fgetc(pf);
    printf("%c\n", ch); // 输出:d


    fseek(pf, 3, SEEK_SET); //文件首部向后偏移三个
    ch = fgetc(pf);
    printf("%c\n", ch); // 输出:d

    fseek(pf, -3, SEEK_END); //文件首部向前偏移三个  末尾的指针是f的后面
    ch = fgetc(pf);
    printf("%c\n", ch); // 输出:d

    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

fseek()移動先の正確なバイト オフセットがわかっているバイナリ ファイルまたはテキスト ファイルに使用する必要があります。テキスト ファイルの場合、fseek()プラットフォームごとの改行文字の違いにより、予期しない結果が発生する可能性があります。fgets()この場合、ファイルを 1 行ずつ読み取るか、ファイルの内容を 1 文字ずつ処理する方が適切です。

5.2 フィート

ftell()現在のファイル位置インジケーター (つまり、ファイル ポインターの位置) を取得するために使用されるファイル内のオフセット。ファイルの先頭からの相対的な現在位置のバイト数を返します。

関数のプロトタイプは次のとおりです。

long int ftell(FILE *stream);

パラメータ:

  • stream:FILE現在の場所にあるファイルを取得することを示すオブジェクトへのポインター。

戻り値:

  • 成功すると、ファイルの先頭からの現在のファイル位置インジケーターのオフセットをバイト単位で表す type の値がftell()返されます。long int
  • エラーが発生した場合、戻り値EOF(通常は -1) はエラーが発生したことを示します。
#include <stdio.h>
int main() {
    
    
    FILE *pf = fopen("test.txt", "r");
    if (pf == NULL) {
    
    
        perror("fopen()");
        return 1;
    }
    //读文件 - 文件中存放abcdef
    int ch = fgetc(pf);
    printf("%c\n", ch);// 输出:a  读完后文件指针往后+1 指向b

    fseek(pf, 2, SEEK_CUR);//从当前文件指针往后偏移2个  (当前是b)
    ch = fgetc(pf);
    printf("%c\n", ch);// 输出:d

    int pos = ftell(pf);//当文件指向d的时候 文件指针往后偏移1个 指向了e
    printf("%d\n", pos);//输出:4   e和a相差4个位置
    //关闭文件  
    fclose(pf);
    pf = NULL;
    return 0;
}

ftell()通常、fseek()ファイル内の特定の場所のオフセットを決定するために使用されます。ファイル ポインタをこの場所に配置するには、最初に呼び出して現在の場所を取得しftell()、次にこの値をfseek()のオフセットとして使用します。

5.3 巻き戻し

rewind()ファイル位置インジケーターをファイルの先頭にリセットするために使用されます。fseek()これは、ファイル ポインターをファイルの先頭に移動するために使用するのと似ていますが、rewind()ファイル ポインターをゼロにするためのより単純な関数です。

関数のプロトタイプは次のとおりです。

void rewind(FILE *stream);

パラメータ:

  • stream:FILEファイル位置インジケーターをリセットするファイルを表すオブジェクトへのポインター。

戻り値:rewind()この関数には戻り値がありません (つまり、戻り値の型は ですvoid)。

#include <stdio.h>
int main() {
    
    
    FILE *pf = fopen("test.txt", "r");
    if (pf == NULL) {
    
    
        perror("fopen()");
        return 1;
    }
    //读文件 - 文件中存放abcdef
    int ch = fgetc(pf);
    printf("%c\n", ch);// 输出:a  读完后文件指针往后+1 指向b

    fseek(pf, 2, SEEK_CUR);//从当前文件指针往后偏移2个  (当前是b)
    ch = fgetc(pf);
    printf("%c\n", ch);// 输出:d

    //记录当前偏移量
    int pos = ftell(pf);//当文件指向d的时候 文件指针往后偏移1个 指向了e
    printf("%d\n", pos);// 输出:4

    //偏移量回到初始位置
    rewind(pf);
    ch = fgetc(pf);
    printf("%c\n", ch);// 输出:a
    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

rewind()この関数は、ファイルのサイズを知ったり、特定のオフセットを使用したりする必要がなく、この関数を呼び出すだけでファイル ポインタがファイルの先頭に戻り、先頭からデータの読み取りまたは書き込みを行うため、非常に便利です。

6. ファイル読み込み終了の判定

6.1 フェフの悪用

ファイル読み取りプロセス中、feof 関数の戻り値を使用してファイルが終了したかどうかを直接判断することはできないことに注意してください。

代わりに、ファイルの読み取りが終了したときに適用され、読み取りが終了できなかったのか、ファイルの終わりに達したかが判断されます。

1. テキストファイルの読み込みが終了したか、戻り値がEOF ( fgetc )或者 NULL ( fgets )

例えば:

fgetc - 読み取りが正常であれば、読み取った文字の ascll コード値を返し、読み取りに失敗した場合は EOF を返します。

fgets - 読み取りが成功した場合は読み取りデータのアドレスを返し、読み取りが失敗した場合は NULL を返します。

fscanf - 読み込みが正常であればフォーマット文字列で指定したデータ数を返し、読み込みに失敗した場合はフォーマット文字列で指定したデータ数よりも少ないデータ数を返します

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);
}

バイナリ ファイルの例:

#include <stdio.h>
enum {
    
    
    SIZE = 5
};

int main() {
    
    
    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);
}

7. ファイルバッファ

ASIC 標準では、データ ファイルの処理に「バッファ ファイル システム」が使用されています。いわゆるバッファ ファイル システムとは、システムがプログラムで使用されるファイルごとにメモリ内に「ファイル バッファ」を自動的に作成することを意味します。メモリからディスクに出力されたデータは、まずメモリ内のバッファに送信され、バッファがいっぱいになった後にまとめてディスクに送信されます。ディスクからコンピュータにデータを読み込む場合、ディスクファイルから読み取ったデータはメモリバッファに入力され、バッファからプログラムデータ領域にデータが1つずつ送られます。バッファのサイズは C コンパイル システムによって決定されます。
ここに画像の説明を挿入

#include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试
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;
}

ここで結論を導き出すことができます

バッファの存在により、C 言語がファイルを操作する場合、ファイル操作の最後にバッファをリフレッシュするか、ファイルを閉じる必要があります。

そうしないと、ファイルの読み取りおよび書き込みで問題が発生する可能性があります。

おすすめ

転載: blog.csdn.net/ikun66666/article/details/131993458