✨✨ 欢送大家来到贝蒂大讲堂✨✨

养成好习惯,先赞后看哦~

所属专栏:C语言学习
贝蒂的主页:Betty‘s blog

1. 什么是文件

文件其实是指一组相干数据的有序汇合。这个数据集有一个名称,叫做文件名。文件通常是驻留在内部介质(如磁盘等)上的,在应用时才调入内存中来。

从文件性能上来讲,个别可分为:程序文件数据文件

1.1 文件名

一个文件要有一个惟一的文件标识,以便用户辨认和援用,这就是文件名
  • ⽂件名蕴含3局部:⽂件门路+⽂件名主⼲+⽂件后缀
  • 例如:c:\code\test.txt

1.2 程序文件

程序文件个别指:源程序文件(后缀为.c),指标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)
  • 源程序文件个别在创立程序目录文件下

![]()

  • 源程序文件通过编译器链接链接器链接能够生成咱们的可执行程序的文件。

1.3 数据文件

⽂件的内容不⼀定是程序,⽽是程序运行时读写的数据,⽐如程序运⾏须要从中读取数据的⽂件,或者输入内容的⽂件。

本章探讨的是数据文件

以前各章所解决数据的输⼊输入都是以终端为对象的,即从终端的键盘输⼊数据,运⾏后果显⽰到显⽰器上。

其实有时候咱们会把信息输入到磁盘上,当须要的时候再从磁盘上把数据读取到内存中使⽤,这⾥解决的就是磁盘上⽂件。

2. 文件的作用

如果没有⽂件,咱们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就失落了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏长久化的保留,咱们就须要使⽤文件

3. 文件的关上与敞开

3.1 流与规范流

(1) 流

咱们程序的数据须要输入到各种外部设备,也须要从外部设备获取数据,不同的外部设备的输⼊输入操作各不相同,为了⽅便程序员对各种设施进⾏⽅便的操作,咱们形象出了的概念,咱们能够把流设想成流淌着字符的河。

C程序针对文件画面键盘等的数据输⼊输入操作都是通过流操作的。⼀般状况下,咱们要想向流⾥写数据,或者从流中读取数据,都是要关上流,而后操作。

(2) 规范流

那为什么咱们从键盘输⼊数据,向屏幕上输入数据,并没有关上流呢?那是因为C语⾔程序在启动的时候,默认关上了3个流:
stdin-规范输⼊流,在⼤少数的环境中从键盘输⼊,scanf函数就是从规范输⼊流中读取数据。
stdout-规范输入流,⼤少数的环境中输入⾄显⽰器界⾯,printf函数就是将信息输入到规范输入流中。
stderr-规范谬误流,⼤少数环境中输入到显⽰器界⾯。

这是默认关上了这三个流,咱们使⽤scanf、printf等函数就能够间接进⾏输⼊输入操作的。stdin、stdout、stderr三个流的类型是: FILE* ,通常称为文件指针
在C语⾔中,就是通过 FILE* 的⽂件指针来保护流的各种操作的。

3.2 文件指针

在缓冲文件系统中,要害的概念是“文件类型指针”,简称“文件指针”

每个被应用的文件都在内存中开拓了一个相应的文件信息区,用来寄存文件的相干信息(如文件的名字,文件状态及文件以后的地位等)。这些信息是保留在一个构造体变量中的。该构造体类型是有零碎申明的,取名【FILE】

例如,VS2022编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

struct _iobuf {        char *_ptr;        int   _cnt;        char *_base;        int   _flag;        int   _file;        int   _charbuf;        int   _bufsiz;        char *_tmpfname;       };typedef struct _iobuf FILE;FILE* pf;//文件指针变量

不同的C编译器的FILE类型蕴含的内容不完全相同,然而大同小异。每当关上一个文件的时候,零碎会依据文件的状况主动创立一个FILE构造的变量,并填充其中的信息,使用者不用关怀细节。

个别都是通过一个FILE的指针来保护这个FILE构造的变量,这样应用起来更加不便。咱们来看看如何创立一个FILE的指针变量

FILE* pf;    //文件指针变量
  • 定义pf是一个指向FILE类型数据的指针变量。能够使pf指向某个文件的文件信息区(是一个构造体变量)。通过该文件信息区中的信息就可能拜访该文件。也就是说,通过文件指针变量可能找到与它关联的文件,以此来进行相干操作。

3.3 文件的关上与敞开

⽂件在读写之前应该先关上⽂件,在使⽤完结之后应该敞开⽂件。这与咱们后面学习的动态内存开拓很相似。

在编写程序的时候,在关上⽂件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了指针和⽂件的关系。

ANSIC规定使⽤ fopen 函数来关上⽂件, fclose 来敞开⽂件。

(1) fopen函数

  1. 头文件#include<stdio.h>
  2. 申明:FILE fopen(const char filename, const char *mode)

    • filename -- 字符串,示意要关上的文件名称。
    • mode -- 字符串,示意文件的拜访模式。
  3. 作用:应用给定的模式 mode 关上 filename 所指向的文件
  4. 返回值:该函数返回一个 FILE 指针。否则返回 NULL,且设置全局变量 errno 来标识谬误。

下表为常见的拜访模式(mode):

文件应用形式含意如果指定文件不存在
“r”(只读)为了输出数据,关上一个曾经存在的文本文件出错
“w”(只写)为了输入数据,关上一个文本文件建设一个新的文件
“a”(追加)向文本文件尾增加数据建设一个新的文件
rb”(只读)为了输出数据,关上一个二进制文件出错
“wb”(只写)为了输入数据,关上一个二进制文件建设一个新的文件
“ab”(追加)向一个二进制文件尾增加数据出错
“r+”(读写)为了读和写,关上一个文本文件出错
“w+”(读写)为了读和写,倡议一个新的文件建设一个新的文件
“a+”(读写)关上一个文件,在文件尾进行读写建设一个新的文件
“rb+”(读写)为了读和写关上一个二进制文件出错
“wb+”(读写)为了读和写,新建一个新的二进制文件建设一个新的文件
“a+”(读写)关上一个二进制文件,在文件尾进行读写建设一个新的文件

(2) fclose函数

  1. 头文件#include<stdio.h>
  2. 申明:int fclose(FILE *stream)

    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了要被敞开的流。
  3. 作用:敞开流 stream。刷新所有的缓冲区
  4. 返回值:如果流胜利敞开,则该办法返回零。如果失败,则返回 EOF。

下列是fopen与fclose具体应用:

int main(){    //关上文件    FILE* pf = fopen("test.txt", "w");    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }        //敞开文件    fclose(pf);    pf = NULL;        //避免野指针    return 0;}

4. 文件的程序读写

4.1 单字符输入输出

(1) fputc函数

  1. 头文件:#include<stdio.h>
  2. 申明:int fputc(int char, FILE *stream)

    • char -- 这是要被写入的字符。该字符以其对应的 int 值进行传递。
    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。
  3. 作用:把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中。
  4. 返回值:如果没有产生谬误,则返回被写入的字符。如果产生谬误,则返回 EOF,并设置谬误标识符。

下列是具体的fputc的应用办法:

#include<stdio.h>int main(){    //关上文件    FILE* pf = fopen("test.txt", "w");    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }    //将abc放进文件    fputc('a', pf);    fputc('b', pf);    fputc('c', pf);    //敞开文件    fclose(pf);    pf = NULL;//避免野指针    return 0;}

如果你想查看写入后果,能够在创立我的项目下找到Debug文件,关上

(2) fgetc函数

  1. 头文件:#include<stdio.h>
  2. 申明:int fgetc(FILE *stream)

    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要在下面执行操作的流。
  3. 作用:从指定的流 stream 获取下一个字符(一个无符号字符)。
  4. 返回值:该函数以无符号 char 强制转换为 int 的模式返回读取的字符,如果达到文件开端或产生读谬误,则返回 EOF。

下列是具体的fputc的应用办法:

#include<stdio.h>int main(){    //关上文件    FILE* pf = fopen("test.txt", "r");//只读    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }    fputc('a', pf);    fputc('b', pf);    fputc('c', pf);    int ch = fgetc(pf);    printf("读出来的字符为:%c\n", ch);    ch = fgetc(pf);    printf("读出来的字符为:%c\n", ch);    ch = fgetc(pf);    printf("读出来的字符为:%c\n", ch);    //敞开文件    fclose(pf);    pf = NULL;//避免野指针    return 0;}

输入后果:

4.2 文本行输入输出

(1) fputs函数

  1. 头文件:#include<stdio.h>
  2. 申明:int fputs(const char str, FILE stream)

    • str -- 这是一个数组,蕴含了要写入的以空字符终止的字符序列。
    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。
  3. 作用:把字符串写入到指定的流 stream 中,但不包含空字符
  4. 返回值:该函数返回一个非负值,如果产生谬误则返回 EOF。

上面是fputs的具体应用办法:

#include<stdio.h>int main(){    //关上文件    FILE* pf = fopen("test.txt", "w");    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }    fputs("hello betty", pf);    //敞开文件    fclose(pf);    pf = NULL;//避免野指针    return 0;}

演示后果:

(2) fgets函数

  1. 头文件:#include<stdio.h>
  2. 申明:char fgets(char str, int n, FILE *stream)

    • str -- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
    • n -- 这是要读取的最大字符数(包含最初的空字符)。通常是应用以 str 传递的数组长度。
    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。
  3. 作用:从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者达到文件开端时,它会进行,具体视状况而定。
  4. 返回值:如果胜利,该函数返回雷同的 str 参数。如果达到文件开端或者没有读取到任何字符,str 的内容放弃不变,并返回一个空指针。如果产生谬误,返回一个空指针。

上面是fgets的具体应用办法:

#include<stdio.h>int main(){    //关上文件    FILE* pf = fopen("test.txt", "r");    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }    fputs("hello betty", pf);    char arr[] = "##########";    fgets(arr, 5, pf);    puts(arr);    //敞开文件    fclose(pf);    pf = NULL;//避免野指针    return 0;}

输入后果:

  • 尽管读取五个字符,然而只会显示四个字符,因为'\0也会默认增加进去

4.3 格式化输入输出

(1) fprintf函数

  1. 头文件:#include<stdio.h>
  2. 申明:int fprintf(FILE stream, const char format, ...)

    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
    • format -- 这是 C 字符串,蕴含了要被写入到流 stream 中的文本。它能够蕴含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需要进行格式化。
  3. 作用:依照肯定格局向输入流输入数据。
  4. 返回值:如果胜利,则返回写入的字符总数,否则返回一个正数。

上面是fprintf的具体应用办法:

typedef struct student {    char name[20];    int height;    float score;}stu;int main(){    stu s = { "beidi", 170, 95.0 };    //写文件    FILE* pf = fopen("test.txt", "w");    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }    fprintf(pf, "%s %d %f", s.name, s.height, s.score);    //敞开文件    fclose(pf);    pf = NULL;//避免野指针    return 0;}

(2) fscanf函数

  1. 头文件:#include<stdio.h>
  2. 申明:int fscanf(FILE stream, const char format, ...)

    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
    • format -- 这是 C 字符串,蕴含了以下各项中的一个或多个:空格字符非空格字符format 说明符。
  3. 作用:依照肯定格局从输出流输出数据。
  4. 返回值:如果胜利,该函数返回胜利匹配和赋值的个数。如果达到文件开端或产生读谬误,则返回 EOF。

上面是fscanf的具体应用办法:

typedef struct student {    char name[20];    int height;    float score;}stu;int main(){    stu s = { "beidi", 170, 95.0 };    //写文件    FILE* pf = fopen("test.txt", "r");    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }    fscanf(pf, "%s %d %f", s.name, &(s.height), &(s.score));    printf("%s %d %f", s.name, s.height, s.score);    //敞开文件    fclose(pf);    pf = NULL;//避免野指针    return 0;}

4.4 二进制输入输出

(1) fwrite函数

  1. 头文件:#include<stdio.h>
  2. 申明:size_t fwrite(const void ptr, size_t size, size_t nmemb, FILE stream)

    • ptr -- 这是指向要被写入的元素数组的指针。
    • size -- 这是要被写入的每个元素的大小,以字节为单位。
    • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
  3. 作用:把 ptr 所指向的数组中的数据写入到给定流 stream 中。
  4. 返回值:如果胜利,该函数返回一个 size_t 对象,示意元素的总数,该对象是一个整型数据类型。如果该数字与 nmemb 参数不同,则会显示一个谬误。

上面是fwrite的具体应用办法:

typedef struct student {    char name[20];    int height;    float score;}stu;int main(){    stu s = { "beidi", 170, 95.0 };    //写文件    FILE* pf = fopen("test.txt", "wb");//二进制写入    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }    fwrite(&s, sizeof(s), 1, pf);    //敞开文件    fclose(pf);    pf = NULL;//避免野指针    return 0;}

  • 二进制数据正常人是无奈看懂的,然而电脑能精确辨认

(2) fread函数

  1. 头文件:#include<stdio.h>
  2. 申明:size_t fread(void ptr, size_t size, size_t nmemb, FILE stream)

    • ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
    • size -- 这是要读取的每个元素的大小,以字节为单位。
    • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
  3. 作用:从给定流 stream 读取数据到 ptr 所指向的数组中
  4. 返回值:胜利读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能产生了一个谬误或者达到了文件开端。

上面是fread的具体应用办法

typedef struct student {    char name[20];    int height;    float score;}stu;int main(){    stu s = {0};    //写文件    FILE* pf = fopen("test.txt", "rb");//二进制写出    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }    fread(&s, sizeof(s), 1, pf);    printf("%s %d %f", s.name, s. height, s.score);    //敞开文件    fclose(pf);    pf = NULL;//避免野指针    return 0;}

4.5 流输入输出

从后面咱们晓得在咱们输入输出时,默认关上stdin - 规范输出流 stdout - 规范输入流stderr - 规范输谬误 。那咱们可不可以利用流来输入输出呢?答案天然是能够的,上面是具体实例:

int main(){    printf("输出前:");    int ch = fgetc(stdin);//输出    printf("输出后:");    fputc(ch, stdout);//输入    return 0;}

还有另外一种办法:

int main(){    printf("输出前:");    int ch = 0;    fscanf(stdin, "%c", &ch);    printf("输出后:");    fprintf(stdout, "%c", ch);    return 0;}

4.6 补充

(1) sprintf与sscanf

  1. 头文件:#include<stdio.h>
  2. 申明:int sprintf(char str, const char format, ...)

    • str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
    • format -- 这是字符串,蕴含了要被写入到字符串 str 的文本。它能够蕴含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需要进行格式化
  3. 作用:将格式化数据转换为字符串
  4. 返回值:如果胜利,则返回写入的字符总数,不包含字符串追加在字符串开端的空字符。如果失败,则返回一个正数。
  1. 头文件:#include<stdio.h>
  2. 申明:int sscanf(const char str, const char format, ...)

    • str -- 这是 C 字符串,是函数检索数据的源。
    • format -- 这是 C 字符串,蕴含了以下各项中的一个或多个:空格字符非空格字符format 说明符。
  3. 作用:将字符串依照肯定格局转换为格式化数据
  4. 返回值:如果胜利,该函数返回胜利匹配和赋值的个数。如果达到文件开端或产生读谬误,则返回 EOF。

下列展现了sprintf与sscanf的具体用法:

typedef struct student {    char name[20];    int height;    float score;}stu;int main(){    char buf[100] = { 0 };    stu s = { "betty", 170, 95.0f };    stu tmp = { 0 };    //将这个构造体的成员转化为字符串    sprintf(buf, "%s %d %f", s.name, s.height, s.score);    printf("%s\n", buf);    //将这个字符串中内容还原为一个构造体数据呢    sscanf(buf, "%s %d %f", tmp.name, &(tmp.height), &(tmp.score));    printf("%s %d %f", tmp.name, tmp.height, tmp.score);    return 0;}

(2) 比照

下表展现了scanf与printf,fscanf与fprintf,sscanf与sprintf之间的区别

函数性能
scanf针对规范输出(键盘)的格式化输出函数
printf针对规范输出出(屏幕)的格式化输入函数
fscanf针对所以输出流的格式化输出函数
fprintf针对所以输入流的格式化输入函数
sscanf从一个字符串中读取一个格式化数据
sprintf把一个格式化数据转换为字符串

5. 文本文件和二进制文件

依据数据的组织模式,数据⽂件被称为⽂本⽂件或者二进制⽂件

  1. 文本文件:以ASCII字符的模式存储的⽂件
  2. 二进制文件:数据在内存中以⼆进制的模式存储的文件

⼀个数据在⽂件中是怎么存储的呢?字符⼀律以ASCII模式存储数值型数据既能够⽤ASCII模式存储,也能够使⽤⼆进制模式存储

如有整数10000,如果以ASCII码的模式输入到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽⼆进制模式输入,则在磁盘上只占4个字节。

  • 字符1的二进制序列:00110001,字符0的二进制序列:00110000

测试代码:

int main(){    int a = 10000;    FILE* pf = fopen("test.txt", "wb");    fwrite(&a, 4, 1, pf);//二进制的模式写到文件中    fclose(pf);    pf = NULL;    return 0;}
  • 右击源文件,增加现有项,将test.txt增加进入

  • 右击test.txt文件,抉择打开方式,抉择二进制编辑器

  • 10 27 00 00便是10000以小端存储的十六进制模式

6. 文件的随机读写

6.1 fseek函数

  1. 头文件:#include<stdio.h>
  2. 申明:int fseek(FILE *stream, long int offset, int whence)

    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
    • offset -- 这是绝对 whence 的偏移量,以字节为单位。
    • whence -- 这是示意开始增加偏移 offset 的地位。
  3. 作用:设置流 stream 的文件地位为给定的偏移 offset,参数 offset 意味着从给定的 whence 地位查找的字节数。
  4. 返回值:如果胜利,则该函数返回零,否则返回非零值。
  • whence偏移offset的三种地位:
常量形容
SEEK_SET文件的结尾
SEEK_CUR文件指针的以后地位
SEEK_END文件的开端

假如文件中放的是字符串“abcdef,上面是fseek的具体应用实例:

int main(){    //关上文件    FILE* pf = fopen("test.txt", "r");    if (pf == NULL)    {        perror(" fopen fail");        return 1;    }    fseek(pf, 4, SEEK_SET);    //从其实地位偏移四个字节    int ch1 = fgetc(pf);    printf("%c ", ch1);    fseek(pf, -3, SEEK_END);    //从完结地位偏移七个个字节         int ch2 = fgetc(pf);    printf("%c ", ch2);    fseek(pf, 1, SEEK_CUR);    //从以后地位偏移一个字节    int ch3 = fgetc(pf);    printf("%c ", ch3);    //敞开文件    fclose(pf);    pf = NULL;//避免野指针    return 0;}

  1. 从起始地位偏移四个字节,输入e
  2. 从开端偏移三个字节,输入d
  3. 此时偏移指向e的地位,再偏移一个字节指向f。

6.2 ftell函数

  1. 头文件:#include<stdio.h>
  2. 申明:long int ftell(FILE *stream)

    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  3. 作用:返回⽂件指针绝对于起始地位的偏移量
  4. 返回值:该函数返回地位标识符的以后值。如果产生谬误,则返回 -1L,全局变量 errno 被设置为一个正值。

咱们能够利用fseek和ftell来计算文件的长度(不蕴含'\0'),下列是代码示例

int main(){    FILE* pFile;    long size;    pFile = fopen("test.txt", "rb");    if (pFile == NULL)         perror("Error opening file");    else    {        fseek(pFile, 0, SEEK_END); //non-portable        size = ftell(pFile);        fclose(pFile);        printf("文件长度为: %ld bytes.\n", size);    }    return 0;}

6.3 rewind函数

  1. 头文件:#include<stdio.h>
  2. 申明:void rewind(FILE *stream)

    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流
  3. 作用:让⽂件指针的地位回到⽂件的起始地位
  4. 返回值:该函数不返回任何值。

rewind经常在文件读与写同时应用时,以不便文件读取。上面是rewind的具体应用实例:

#include <stdio.h>int main(){    int n;    FILE* pFile;    char buffer[27];    pFile = fopen("myfile.txt", "w+");    for (n = 'A'; n <= 'Z'; n++)        fputc(n, pFile);//放入26个字母    rewind(pFile);//回到起始地位,不便读取    fread(buffer, 1, 26, pFile);//读取·    fclose(pFile);    buffer[26] = '\0';//字符串的完结标识    printf(buffer);    return 0;}

7. ⽂件读取完结的断定

7.1 被谬误应用的 feof

在咱们学习C语言文件操作的过程中,经常会有人误认为feof是判断文件是否完结的函数,其实这并不精确。feof 的作⽤是:当⽂件读取完结的时候,判断是读取完结的起因是:遇到⽂件尾完结还是文件读取失败完结

7.2 常见的完结标记

函数完结标记
fgetc如果读取失常,返回读取到的字符的ASCLL码值 如果读取失败,返回EOF
fgets如果读取失常,返回读取到的数据的地址 如果读取失败,返回NULL
fscanf如果读取失常,返回的是格局串中指定的数据个数 如果读取失败,返回的是小于格局串中指定的数据个数
fread如果读取失常,返回的是等于要读取的数据个数 如果读取失败,返回的是小于要读取的数据个数

8. 文件缓冲区

ANSIC 规范采纳缓冲文件系统解决的数据文件的,所谓缓冲文件系统是指零碎主动地在内存中为程序中每一个正在应用的文件开拓一块“文件缓冲区”。

  • 从内存向磁盘输入数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。
  • 如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输⼊到内存缓冲区(充斥缓冲区),而后再从缓冲区一一地将数据送到程序数据区(程序变量等)
  • 缓冲区的⼤⼩依据C编译系统决定的。

咱们能够利用下列代码证实缓冲区的存在:

include <stdio.h>#include <windows.h>//VS2019 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;}

刷新缓冲区前:

刷新缓冲区后:

  • 因为有缓冲区的存在,C语⾔在操作⽂件的时候,须要做刷新缓冲区或者在⽂件操作完结的时候敞开⽂件。如果不做,可能导致读写⽂件的问题。