文 件 操 作

目录

 1.为什么使用文件

2. 什么是文件

2.1 程序文件 

2.2 数据文件

2.3 文件名

流的概念及分类

文本文件与二进制文件

3. 文件的打开和关闭

  3.1 文件指针

 3.2 文件的打开和关闭  

4. 文件的顺序读写

接字符串输入输出

按格式化输入输出

按二进制方式读写数据块

被错误使用的feof

文件的随机读写

缓冲和非缓冲文件系统


今天我们来简单了解一下C语言中文件操作的具体内容与细节。

 1.为什么使用文件

我们前面学习结构体时,写了通讯录的程序,当通讯录运行起来的时候,可以给通讯录中增加、删除数据,此时数据是存放在内存中,当程序退出的时候,通讯录中的数据自然就不存在了,等下次运行通讯录程序的时候,数据又得重新录入,如果使用这样的通讯录就很难受。 

我们在想既然是通讯录就应该把信息记录下来,只有我们自己选择删除数据的时候,数据才不复存在。这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据库等方式。

使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。
 

2. 什么是文件

磁盘上的文件是文件。
但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

2.1 程序文件 

包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

2.2 数据文件

 文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文
 件,或者输出内容的文件。


 本章讨论的是数据文件。
 在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显
 示器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理
的就是磁盘上文件。

2.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
为了方便起见,文件标识常被称为文件名。

流的概念及分类

I/O 设备的多样性及复杂性,给程序设计者访问这些设备带来了很大的难度和不便。为此,ANSIC 的 I/O 系统即标准 I/O 系统,把任意输入的源端或任意输出的终端,都抽象转换成了概念上的“标准 I/O 设备”或称“标准逻辑设备”。程序绕过具体设备,直接与该“标准逻辑设备”进行交互,这样就为程序设计者提供了一个不依赖于任何具体 I/O 设备的统一操作接口,通常把抽象出来的“标准逻辑设备”或“标准文件”称作“流”。

把任意 I/O 设备,转换成逻辑意义上的“标准 I/O 设备”或“标准文件”的过程,并不需要程序设计者感知和处理,是由标准 I/O 系统自动转换完成的。故从这个意义上,可以认为任意输入的源端和任意输出的终端均对应一个“流”。

流按方向分为:输入流和输出流。从文件获取数据的流称为输入流,向文件输出数据称为输出流。

例如,从键盘输入数据然后把该数据输出到屏幕上的过程,相当于从一个文件输入流(与键盘相关)中输入(读取)数据,然后通过另外一个文件输出流(与显示器相关)把获取的数据输出(写入)到文件(显示器)上。

流按数据形式分为:文本流和二进制流。文本流是 ASCII 码字符序列,而二进制流是字节序列。

文本文件与二进制文件

根据文件中数据的组织形式的不同,可以把文件分为:文本文件和二进制文件。
  • 文本文件:把要存储的数据当成一系列字符组成,把每个字符的 ASCII 码值存入文件中。每个 ASCII 码值占一个字节,每个字节表示一个字符。故文本文件也称作字符文件或 ASCII 文件,是字符序列文件。
  • 二进制文件:把数据对应的二进制形式存储到文件中,是字节序列文件。

例如数据 123,如果按文本文件形式存储,把数据看成三个字符:'1'、'2'、'3' 的集合,文件中依次存储各个字符的 ASCII 码值,格式如表 1 所示。
表 1 数据 123 的文本存储形式
字符'1''2''3'
ASCII(十进制)495051
ASCII(二进制)0011 00010011 00100011 0011

如果按照二进制文件形式存储,则把数据 123 看成整型数,如果该系统中整型数占 4 个字节,则数据 123 二进制存储形式的 4 个字节如下。

0000 0000 0000 0000 0000 0000 0111 1011

  

3. 文件的打开和关闭

  3.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指向某个文件的文件信息区(是一个结构体变
量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联
的文件。

 3.2 文件的打开和关闭
  

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了
指针和文件的关系。
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。

/打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

函数参数

  1. filename:文件名,包括路径,如果不显式含有路径,则表示当前路径。例如,“D:\\f1.txt”表示 D 盘根目录下的文件 f1.txt 文件。“f2.doc”表示当前目录下的文件 f2.doc。
  2. mode:文件打开模式,指出对该文件可进行的操作。常见的打开模式如 “r” 表示只读,“w” 表示只写,“rw” 表示读写,“a” 表示追加写入。更多的打开模式如表 2 所示。

打开方式如下:

文件使用方式含义如果指定文件不存在
“r”(只读)为了输入数据,打开一个已经存在的文本文件出错
“w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
“a”(追加)向文本文件尾添加数据建立一个新的文件
“rb”(只读)为了输入数据,打开一个二进制文件出错
“wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件
“ab”(追加)向一个二进制文件尾添加数据出错
“r+”(读写)为了读和写,打开一个文本文件出错
“w+”(读写)为了读和写,建议一个新的文件建立一个新的文件
“a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写)为了读和写打开一个二进制文件出错
“wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

返回值:打开成功,返回该文件对应的 FILE 类型的指针;打开失败,返回 NULL。故需定义 FILE 类型的指针变量,保存该函数的返回值。可根据该函数的返回值判断文件打开是否成功。 

实例代码:

/* fopen fclose example */
#include <stdio.h>
int main ()
{
FILE * pFile;
//打开文件
pFile = fopen ("myfile.txt","w");
//文件操作
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
//关闭文件
fclose (pFile);
}
return 0;
}

4. 文件的顺序读写

对文件读取操作完成后,如果从文件中读取到的每个数据的顺序与文件中该数据的物理存放顺序保持一致,则称该读取过程为顺序读取;同理,对文件写入操作完成后,如果文件中所有数据的存放顺序与各个数据被写入的先后顺序保持一致,则称该写入过程为顺序写入。

功能函数名适用于
字符输入函数fgetc所有输入流
字符输出函数fputc所有输出流
文本行输入函数fgets所有输入流
文本行输出函数fputs所有输出流
格式化输入函数fscanf所有输入流
格式化输出函数fprintf所有输出流
二进制输入fread文件
二进制输出fwrite文件

换字符输入输出

c 语言中提供了从文件中逐个输入字符及向文件中逐个输出字符的顺序读写函数 fgetc 和 fputc 及调整文件读写位置到文件开始处的函数 rewind。这些函数均在标准输入输出头文件 stdio.h 中。

字符输入函数 fgetc 的函数原型为:

int fgetc (FILE *fp);

 所在头文件:<stdio.h>。

函数功能:从文件指针 fp 所指向的文件中输入一个字符。输入成功,返回该字符;已读取到文件末尾,或遇到其他错误,即输入失败,则返回文本文件结束标志 EOF(EOF 在 stdio.h 中已定义,一般为 -1)。

注意:由于 fgetc 是以 unsigned char 的形式从文件中输入(读取)一个字节,并在该字节前面补充若干 0 字节,使之扩展为该系统中的一个 int 型数并返回,而非直接返回 char 型。当输入失败时返回文本文件结束标志 EOF 即 -1,也是整数。故返回类型应为 int 型,而非 char 型。

如果误将返回类型定义为 char 型,文件中特殊字符的读取可能会出现意想不到的逻辑错误。

由于在 C 语言中把除磁盘文件外的输入输出设备也当成文件处理,故从键盘输入字符不仅可以使用宏 getchar() 实现,也可以使用 fgetc (stdin) 实现。其中,stdin 指向标准输入设备—键盘所对应的文件。stdin 不需要人工调用函数 fopen 打开和 fclose 关闭。

字符输出函数 fputc 的函数原型为:

int fputc (int c, FILE *fp);

所在头文件:<stdio.h>

函数功能:向 fp 指针所指向的文件中输出字符 c,输出成功,返回该字符;输出失败,则返回 EOF(-1)。

向标准输出设备屏幕输出字符变量 ch 中保存的字符,不仅可以使用宏 putchar(ch) 实现,也可以使用 fputc (ch,stdout); 实现。其中,stdout 指向标准输出设备—显示器所对应的文件。stdout 也不需要人工调用函数 fopen 打开和 fclose 关闭。

对一个文件进行读写操作时,经常会把一个文件中读写位置重新调整到文件的开始处,可以使用函数 rewind 实现。

文件读写位置复位函数 rewind 的函数原型为:

void rewind (FILE *fp);

 所在头文件:<stdio.h>

函数功能:把 fp 所指向文件中的读写位置重新调整到文件开始处。

接字符串输入输出

下面主要介绍文件中常见的字符串输入、输出函数 fgets 和 fputs。

字符串输入函数 fgets 的函数原型为:

char * fgets (char *s, int size, FILE * fp);

所在头文件:<stdio.h>

函数功能:从 fp 所指向的文件内,读取若干字符(一行字符串),并在其后自动添加字符串结束标志 '\0' 后,存入 s 所指的缓冲内存空间中(s 可为字符数组名),直到遇到回车换行符或已读取 size-1 个字符或已读到文件结尾为止。该函数读取的字符串最大长度为 size-1。

参数 fp:可以指向磁盘文件或标准输入设备 stdin。

返回值:读取成功,返回缓冲区地址 s;读取失败,返回 NULL。

说明:fgets 较之 gets 字符串输入函数是比较安全规范的。因为 fgets 函数可由程序设计者自行指定输入缓冲区 s 及缓冲区大小 size。即使输入的字符串长度超过了预定的缓冲区大小,也不会因溢出而使程序崩溃,而是自动截取长度为 size-1 的串存入 s 指向的缓冲区中。
 
字符串输出函数 fputs 的函数原型为: 

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

所在头文件:<stdio.h>

函数功能:把 str(str 可为字符数组名)所指向的字符串,输出到 fp 所指的文件中。

返回值:输出成功,返回非负数;输出失败,返回EOF(-1)。

按格式化输入输出

文件操作中的格式化输入输出函数 fscanf 和 fprintf 一定意义上就是 scanf 和 printf 的文本版本。程序设计者可根据需要采用多种格式灵活处理各种类型的数据,如整型、字符型、浮点型、字符串、自定义类型等。

文件格式化输入函数 fscanf 的函数原型为: 

int fscanf (文件指针,格式控制串,输入地址表列);

在头文件:<stdio.h>

函数功能:从一个文件流中执行格式化输入,当遇到空格或者换行时结束。注意该函数遇到空格时也结束,这是其与 fgets 的区别,fgets 遇到空格不结束。

返回值:返回整型,输入成功时,返回输入的数据个数;输入失败,或已读取到文件结尾处,返回 EOF(-1)。

故一般可根据该函数的返回值是否为 EOF 来判断是否已读到文件结尾处。

例如,若文件 f1.dat 中保存了若干整数,各整数之间用空格间隔,从文件中读取两个整数,依次保存到两个整型变量中。程序代码段如下。

int a,b;
FILE *fp=fopen("f1.dat","r");
if(NULL==fp)
{
    printf ("Failed to open the file!\n");
    exit (0);
}
fscanf (fp,"%d%d",&a,&b) ; //从fp所指文件中读取一个整数保存到变量a中
fclose(fp);

 如果 f1.dat 中的整数用逗号间隔,则读取两个整数时,函数 fscanf 的调用格式如下所示。

fscanf (fp,"%d,%d", &a, &b); //两个%d之间也必须用逗号隔开

文件格式化输出函数 fprintf 的函数原型为: 

int fprintf (文件指针,格式控制串,输出表列);

 所在头文件:<stdio.h>

函数功能:把输出表列中的数据按照指定的格式输出到文件中。

返回值:输出成功,返回输出的字符数;输出失败,返回一负数。

例如,向当前目录文件file.txt中输入一个学生的姓名、学号和年龄,采用文本方式,参考代码如下。

#include<stdio.h>
#include<stdlib.h>
int main (void)
{
    FILE *fp=fopen("file.txt","w");
    char name[ 10] ="张三";
    char no[15]="20170304007";
    int age=17;
    if(NULL==fp)
    {
        printf ("Failed to open the file !\n");
        exit (0);
    }
    fprintf(fp,"%s\t%s\t%d\n",name,no,age);
    fclose(fp);
    return 0;
}

 运行程序后,当前目录下生成了 file.txt 文件,并且其内容为:
张三  20170304007  17

按二进制方式读写数据块

 接下来介绍按块读写数据的函数 fread 和 fwrite,这两个函数主要应用于对二进制文件的读写操作,不建议在文本文件中使用。接着介绍了 fread 读取二进制文件时,判断是否已经到达文件结尾的函数 feof。

数据块读取(输入)函数 fread 的函数原型为:

unsigned fread (void *buf, unsigned size, unsigned count, FILE* fp);

所在头文件:<stdio.h>

函数功能:从 fp 指向的文件中读取 count 个数据块,每个数据块的大小为 size。把读取到的数据块存放到 buf 指针指向的内存空间中。

返回值:返回实际读取的数据块(非字节)个数,如果该值比 count 小,则说明已读到文件尾或有错误产生。这时一般采用函数 feof 及 ferror 来辅助判断。

函数参数:

  • buf:指向存放数据块的内存空间,该内存可以是数组空间,也可以是动态分配的内存。void类型指针,故可存放各种类型的数据,包括基本类型及自定义类型等。
  • size:每个数据块所占的字节数。
  • count:预读取的数据块最大个数。
  • fp:文件指针,指向所读取的文件。


数据块写入(输出)函数 fwrite 的函数原型为: 

unsigned fwrite (const void *bufAunsigned size,unsigned count,FILE* fp);

 所在头文件:<stdio.h>

函数功能:将 buf 所指向内存中的 count 个数据块写入 fp 指向的文件中。每个数据块的大小为 size。

返回值:返回实际写入的数据块(非字节)个数,如果该值比 count 小,则说明 buf 所指空间中的所有数据块已写完或有错误产生。这时一般采用 feof 及 ferror 来辅助判断。

函数参数:

  • buf:前加const的含义是buf所指的内存空间的数据块只读属性,避免程序中有意或无意的修改。
  • size:每个数据块所占的字节数。
  • count:预写入的数据块最大个数。
  • fp:文件指针,指向所读取的文件。

注意:使用 fread 和 fwrite 对文件读写操作时,一定要记住使用“二进制模式”打开文件,否则,可能会出现意想不到的错误。

在操作文件时,经常使用 feof 函数来判断是否到达文件结尾。

feof 函数的函数原型为:

int feof (FILE * fp);

 所在头文件:<stdio.h>

函数功能:检查 fp 所关联文件流中的结束标志是否被置位,如果该文件的结束标志已被置位,返回非 0 值;否则,返回 0。

需要注意的是:
1) 在文本文件和二进制文件中,均可使用该函数判断是否到达文件结尾。

2) 文件流中的结束标志,是最近一次调用输入等相关函数(如 fgetc、fgets、fread 及 fseek 等)时设置的。只有最近一次操作输入的是非有效数据时,文件结束标志才被置位;否则,均不置位。

被错误使用的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);
}

文件的随机读写

以上介绍的都是文件的顺序读写操作,即每次只能从文件头开始,从前往后依次读写文件中的数据。在实际的程序设计中,经常需要从文件的某个指定位置处开始对文件进行选择性的读写操作,这时,首先要把文件的读写位置指针移动到指定处,然后再进行读写,这种读写方式称为对文件的随机读写操作。

C 语言程序中常使用 rewind、fseek 函数移动文件读写位置指针。使用 ftell 获取当前文件读写位置指针。

函数 fseek 的函数原型为:

int fseek(FI:LE *fp, long offset, int origin);

所在头文件:<stdio.h>

函数功能:把文件读写指针调整到从 origin 基点开始偏移 offset 处,即把文件读写指针移动到 origin+offset 处。

函数参数:

1) origin:文件读写指针移动的基准点(参考点)。基准位置 origin 有三种常量取值:SEEK_SET、SEEK_CUR 和 SEEK_END,取值依次为 0,1,2。

SEEK_SET:文件开头,即第一个有效数据的起始位置。
SEEK_CUR:当前位置。
SEEK_END:文件结尾,即最后一个有效数据之后的位置。注意:此处并不能读取到最后一个有效数据,必须前移一个数据块所占的字节数,使该文件流的读写指针到达最后一个有效数据块的起始位置处。

2) offset:位置偏移量,为 long 型,当 offset 为正整数时,表示从基准 origin 向后移动 offset 个字节的偏移;若 offset 为负数,表示从基准 origin 向前移动 |offset| 个字节的偏移。

返回值:成功,返回 0;失败,返回 -1。

例如,若 fp 为文件指针,则 seek (fp,10L,0); 把读写指针移动到从文件开头向后 10 个字节处。 fSeek(fp,10L,1); 把读写指针移动到从当前位置向后 10 个字节处。 fseek(fp,-20L,2); 把读写指针移动到从文件结尾处向前 20 个字节处。

调用 fseek 函数时,第三个实参建议不要使用 0、1、2 等数字,最好使用可读性较强的常量符号形式,使用如下格式取代上面三条语句。

fseek(fp,10L,SEEK_SET);
fseek(fp,10L,SEEK_CUR);
fseek(fp,-20L,SEEK_END);

函数 ftell 的函数原型:

long ftell (FILE *fp);

所在头文件:<stdio.h>

函数功能:用于获取当前文件读写指针相对于文件头的偏移字节数。

例如,分析以下程序,输出其运行结果。

#include<stdio.h>
#include<stdlib.h>
#define N 3 //动物数
typedef struct {
    char name[10];
    int age;
    char duty[20];
}Animal;
int main (void)
{
    Animal a[N] = {{"兔朱迪",5, "交通警察"}, {"尼克", 8, "协警"},{"闪电",10, "车管所职工"}},t;
    int i;
    FILE *fp=fopen ("Animal_Info.bat", "wb+");
    if(NULL==fp)
    {
        printf("Failed to open the file!\n");
        exit (0);
    }
    fwrite(a,sizeof(Animal),N,fp);
    fprintf (stdout, "%s\t%s\t%s\n", "名字","年龄","职务");
    for(i=1;i<=N;i++)
    {
        fseek(fp,0-i*sizeof(Animal),SEEK_END);
        fread(&t,sizeof(Animal),1,fp);
        fprintf (stdout, "%s\t%d\t%-s\n", t.name,t.age,t.duty);
    }
    fclose(fp);
    return 0;
}

运行结果为:
名字    年龄    职务
闪电    10      车管所职工
尼克    8       协警
兔朱迪  5       交通警察

缓冲和非缓冲文件系统

C语言中文件系统可分为两大类,一种是缓冲文件系统也称为标准文件系统,另一种是非缓冲文件系统。ANSI C 标准中只采用缓冲文件系统。

缓冲文件系统:系统自动为每个打开的文件在内存开辟一块缓冲区,缓冲区的大小一般由系统决定。当程序向文件中输出(写入)数据时,程序先把数据输出到缓冲区,待缓冲区满或数据输出完成后,再把数据从缓冲区输出到文件;当程序从文件输入(读取)数据时,先把数据输入到缓冲区,待缓冲区满或数据输人完成后,再把数据从缓冲区逐个输入到程序。

非缓冲文件系统:系统不自动为打开的文件开辟内存缓冲区,由程序设计者自行设置缓冲区及大小。

程序每一次访问磁盘等外存文件都需要移动磁头来定位磁头扇区,如果程序频繁地访问磁盘文件,会缩短磁盘的寿命,况且速度较慢,与快速的计算机内存处理速度不匹配。

带缓冲区文件系统的好处是减少对磁盘等外存文件的操作次数,先把数据读取(写入)到缓冲区中,相当于把缓冲区中的数据一次性与内存交互,提髙了访问速度和设备利用率。

一般把带缓冲文件系统的输入输出称作标准输入输出(标准 I/O),而非缓冲文件系统的输入输出称为系统输入输出(系统 I/O)。

ANSI C 为正在使用的每个文件分配一个文件信息区,该信息区中包含文件描述信息、 该文件所使用的缓冲区大小及缓冲区位置、该文件当前读写到的位置等基本信息。这些信息保存在一个结构体类型变量中,该结构体类型为 FILE 在 stdio.h 头文件中定义,不允许用户改变。

每个 C 编译系统 stdio.h 文件中的 FILE 定义可能会稍有差别,但均包含文件读写的基本信息。

#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语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文
件。
如果不做,可能导致读写文件的问题
 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谁家的攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值