1、 在前面章节的阐述中,已多次涉及到微型计算机的输入输出操作,这些输入输出操作仅对常规输入输出设备进行:从键盘输入数据,或将数据从显示器或打印机输出。通过这些常规输入输出设备,有效地实现了微型计算机与用户的联系。然而,在实际应用系统中,仅仅使用这些常规外部设备是很不够的。使用微型计算机解决实际问题时往往需要处理大量的数据;并且希望这些数据不仅能被本程序使用,而且也能被其他程序使用。通常在计算机系统中,一个程序运行结束后,它所占用的内存空间将被全部释放,该程序涉及的各种数据所占有的内存空间也将被其他程序或数据占用而不能被保留。为保存这些数据,必须将它们以文件形式存储在外存储器(如磁盘、磁带)中;当
2、其他程序要使用这些数据,或该程序还要使用这些数据时,再以文件形式将数据从外存读入内存。尤其在用户处理的数据量较大,数据存储要求较高,处理功能需求较多的场合,应用程序总要使用文件操作功能。12.1.1 文件 从计算机操作系统的概念看,文件是指存放在外存储器上的信息的集合。在微型计算机系统中,使用的外存储器主要是磁盘。磁盘上的所有信息均以文件的形式存储,每个文件具有一个唯一的名称,通过名称对文件进行读、写、修改或删除等操作。文件的命名方法随计算机系统不同而有所差异,在DOS操作系统中文件名称由文件名和扩展名两部分组成,两部分之间用“.”号分隔,如:DATAl.C、TURBO.EXE、COMMAND
3、.COM等。规定文件名最多由8个字符组成,扩展名由3个字符组成。文件可以从不同的角度进行分类,例如,按照文件保存的内容区分,磁盘文件可以分为程序文件和数据文件。程序文件保存的是程序,数据文件用于保存数据。程序文件的读写操作一般由系统完成,数据文件的读写往往由应用程序实现。前面用到的计算机常规输入输出设备也完成类似的功能,因此,从广义的角度看,这些外部设备也都可以看作是一种设备文件,也可以给它们取一个唯一的文件名,对它们的操作也可用与磁盘文件相同的方法去完成。例如,在DOS操作系统中,将打印机定义成名为PRN的设备文件,当向该文件写入信息时,实际上就是打印输出;将键盘定义为名字是CON的设备文件
4、,当从该文件读出信息时,实际上就是从键盘接收键入的字符。这种将物理设备看作是一种逻辑文件,用与磁盘文件操作相同的命令进行操作的做法,可以简化程序设计,方便了用户。总之,从广义上说,文件是指信息输入和输出的对象,磁盘文件、键盘、显示器、打印机等均可视为文件。C语言中采用了类似的做法。C语言中提供了丰富的IO库函数,利用这些库函数完成对各种数据文件及设备文件的操作。12.1.2 常用的文件类型 1.文本文件 文本文件又称ASCII码文件(也称字符文件或正文文件),它是由一个个占用一个字节存储空间的ASCII字符组成的,每一个字符都被编成ASCII码存储,数据在内存中的表现形式与数据本身不一致,必须
5、由系统进行一定的转换。正因为每个ASCII码对应一个字符,文本文件的输出就与字符一一对应,便于对字符进行逐一处理,也便于输出字符。例如,整数11111占5个字节。文本文件由文本行组成,每行可含0到多个字符,并以换行符n结尾,整个文本的结束标志是0 x1a。在用文本向计算机输入时,将回车换行符(r和n)转换成一个换行符(n),在输入时把换行符转换成回车和换行两个字符。2.二进制文件 二进制文件中的数据与其在内存中二进制表示是一致的,一个字节不一定表示一个数据,其在内存中的存储值与数值本身是相同的。例如,2978这个整数,在文本文件中用其ASCII码表示为:2 9 7 8 505755561011
6、10100010它只需要占用2个字节。二进制文件也不做像文本文件那样的从回车换行符到换行符之间的转换。即将数字表示成对应的字符序列。这个整数有4位数字,共用了4个字符;一个字符占一个字节,故共用了4个字节。而在二进制文件中,该数表示成相应的二进制数字:Turbo C语言规定,在二进制存储形式中,整型数用2个字节表示,长整型用4个字节表示,实型数(浮点数)用4个字节表示,双精度数用8个字节表示。一般地说,二进制文件节省存储空间,并且由于在输入时不需要把字符代码先转换成二进制形式再送入内存,在输出时也不需要把数据由二进制形式转换为字符代码再输出,因而输入输出速度快。用户程序在实用中,从节省时间和空
7、间的要求考虑,一般选用二进制文件。但是如果用户准备的数据是作为文档使用阅读的,则一般使用字符文件,它们可以方便、快捷地通过显示器或打印机直接输出 C语言把所有的外设当作文件对待,这样的文件称为设备文件,并由系统给这些设备文件命名。例如,前面提过的打印机的设备文件名是PRN,向PRN输出数据,就是向打印机输出打印数据,C中常用的标准设备文件名如下:3.设备文件和流 CON:键盘(或KYBD)CON:显示器(或SCRN)PRN:打印机(或LPT1)AUX:异步通信口(或COM1)另外,系统还命名了三个标准设备文件的文件结构体指针,如下所示:stdin:标准输入文件结构体指针(由系统分配为键盘)st
8、dout:标准输出文件结构体指针(由系统分配为显示器)stderr:标准错误输出文件结构体指针(由系统分配为显示器)流(stream)是程序输入输出的一个连续的数据序列,它实际上是文件输入输出的一种状态形式。因此,一个C文件就是一个字节流或二进制流。在C语言中,所有的流均以文件形式出现,包括设备文件,这种文件又称为流式文件。12.1.3 C语言的输入输出操作 由于相对于内存储器而言,磁盘是慢速设备。在C语言的文件操作中,如果每向磁盘写入一个字节或读出一个字节的数据,都要启动磁盘操作,将会大大降低系统的效率,而且还会对磁盘驱动器的使用寿命带来不利影响。为此在文件系统中往往使用缓冲技术,即系统在内
9、存中为每一个正在读写的文件开辟一个“缓冲区”,利用缓冲区完成文件读写操作。当从磁盘文件读数据时,应用程序并不直接从磁盘文件读取数据,而是先由系统将一批数据从磁盘取入内存“输入缓冲区”中,然后再由应用程序的读操作从缓冲区依次将数据送给程序中的接收变量,供程序处理。其过程如图12.1a所示。磁盘文件内存程序数据区缓冲区磁盘文件(a)读磁盘文件内存程序数据区缓冲区(b)写磁盘文件图12.1 磁盘文件读写操作 在向磁盘文件写入数据时,先将程序中有关变量或表达式的值送到“输出缓冲区”中,待缓冲区装满后,才由系统将缓冲区的数据一次写入磁盘文件中,如图12.1b所示。这种利用缓冲区将对磁盘文件的频繁逐次访问
10、变为批量访问的做法称为标准文件操作,对应的磁盘文件系统称为缓冲文件系统,也称标准文件系统或高层文件系统。不使用缓冲区的磁盘文件系统成为非缓冲文件系统,也称非标准文件系统或低层文件系统。标准文件系统功能强,使用方便,由系统代替用户做了许多事情,提供了许多方便。非标准文件系统则直接依赖于操作系统,通过操作系统的功能直接对文件进行操作,因而被称为低层文件系统。用C语言编程时,若使用非标准文件系统,要求编程者熟悉操作系统,善于利用系统的功能,编程难度大一些,但程序的执行效率高,占用内存资源较少。新的ANSI标准推荐使用标准文件系统。C语言中,无论是使用标准文件系统还是非标准文件系统,都是利用IO库函数
11、完成文件操作的。12.1.4 文件存取方式 C语言中,文件被看作是字节序列,或称二进制流。即C语言的数据文件由顺序存放的一连串字节(字符)组成,没有记录的界限,因此,C语言的文件称作流式文件,文件存取操作的数据单位是字节,允许存取一个字节和任意多个字节,这样有效地增加了文件操作的灵活性。标准IO提供了4种文件存取方法:(1)读写一个字符。(2)读写一个字符串,将多个字符组成的字符串写入文件或从文件中读出。(3)格式化读写,根据格式控制指定的数据格式对数据进行转换存取。(4)成块读写,也称作按记录读写。C语言的文件虽然是按字节流存放,但可以按记录存取多个字节的数据。对应于以上4种文件存取方式,C
12、语言有相应的函数完成。4种存取方式和C语言的对应的函数关系如图12.2所示。文件的字节流将多个字节作为一个数据存取freadfwrite字符存取fgetcfputc字符串存取fgetsfputs例如 读取多个字节格式存取fscanffprintf例如,将两个字节的数据作为整数存取图12.2 四种文件存取方式与函数12.2.1 文件结构指针 在C语言程序中当建立或调用一个磁盘文件时,必须了解如下信息:与该文件对应的内存缓冲区的地址、文件当前的读写位置、文件操作的方式、是文本文件还是二进制文件、是读操作还是写操作等。标准文件系统为每一个文件开辟一个“文件信息区”,用于存放上述这些信息。“文件信息区
13、”在内存中,是一个由系统定义的结构体变量,该变量具有FILE的数据结构。FILE数据结构一般定义在stdio.h头文件中,定义如下:type structshor level;unsigned flags;char fd;unsigned char hild;short bsize;unsigned char *buffer;unsigned char *curp;unsigned istemp;short token;FILE;这是Turbo C中使用的定义,不同的C编译程序可能使用不同的定义,即结构中的字段名、字段个数、字段作用等都可能不同,但基本含义变化不会太大,因为它最终都要通过操作系
14、统去控制这些文件。读者对这些内容不必深究。每当程序打开一个文件(若该文件不存在,则表示要建立文件;若文件已存在,则打开就意味着要对该文件进行读写),系统就在内存建立一个与该文件对应的FILE结构体变量。有几个文件就建立几个这样的结构体变量,分别存放各文件的有关信息。同时返回对应FILE结构指针(地址)。这样,对该文件的操作,都以该指针为参考,用户无需对这个结构的内容进行控制。程序中不用变量名来标识结构体变量,而是设置一个指向该结构体变量的指针变量,通过它来访问结构体变量,例如:FILE *fp;便定义了一个FILE结构体变量。当程序打开一个文件,就得到对应FILE结构指针。只要把该指针赋给指针
15、变量fp,fp就指向了这个FILE结构体变量,也就是指向这个文件了。需要注意的是,不要把文件指针与FILE结构指针混为一谈,它们代表两个不同的地址。文件指针指出了对一个文件当前要读写的数据位置。而FILE结构指针指出已打开的文件所对应的FILE结构在内存的地址,实际上它本身也包含了文件指针的信息。12.2.2 文件的打开 对磁盘文件的操作包括打开文件、读文件、写文件、关闭文件或删除文件等操作。任何一个文件操作,都必须先打开,后读或写;读写完成后,最后都应关闭文件。所谓打开文件,是在程序和系统之间建立起联系,程序把所要操作的文件的有关信息,如文件名、文件操作方式(读、写或读写)等通知给系统。从实
16、质上看,打开文件表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,此后用户程序就可用此FILE指针来实现对指定文件的存取操作。C语言程序标准文件的打开操作用fopen()函数实现,其调用格式为:FILE*fopen(char*filename,char*mode);fopen()打开一个filename指向的文件,文件操作方式由mode的值决定。例如,fopen(“datafile.dat”,“r”);表示打开名为datafile.dat的文件,文件操作方式设定为“只读”方式(即只能从文件读取数据,不能向文件写入数据)。一般文件名需要用双引号括起来,文件名中也
17、可以包含用双反斜线隔开的路径名。文件操作方式规定如表12.1所示。表表12.1 C语言文件操作方式语言文件操作方式 文件操作方式 含 义 r(只读)为只读打开一个字符文件 w(只写)为只写打开一个字符文件,文件指针指向文件首部 a(追加)打开字符文件,指向文件尾在已存在的文件中追加数据 rb(只读)为只读打开一个二进制文件 wb(只写)为只写打开一个二进制文件 续表 ab(追加)打开二进制文件,以向文件追加数据 r+(读写)以读写方式打开一个已存在的字符文件 w+(读写)为读写建立一个新的字符文件 a+(读写)为读写打开一个字符文件,进行追加 rb+(读写)为读写打开一个二进制文件 wb+(读
18、写)为读写建立一个新的二进制文件 ab+(读写)为读写打开一个二进制文件进行追加 说明:(1)用r方式打开的文件只能在该文件已经存在的条件下向计算机输入数据。(2)用w方式打开的文件只能向该文件写数据,并且在该文件不存在的情况下,则建立以指定名字命名的文件,如果已经存在该文件,则在打开时删去该文件,然后重新建立一个新文件。(3)用a方式向文件尾追加新的数据,要求文件必须首先存在。(4)用r+、w+、a+方式打开的文件即可以用来输入数据,也可以用来输出数据。其它原理与前述三点相同。(5)当用fopen()函数成功地打开一个文件时,该函数将返回一个FILE指针;如果文件打开操作失败,则函数返回值是
19、一个NULL空指针。fopen()函数的返回值应当立即赋给一个PIlE结构指针变量,以便以后能通过该指针变量来访问这个文件,否则此函数的返回值就会丢失而导致程序无法对此文件进行操作。例如,若想打开filel文件进行写操作,可用下面的方法:FILE *fpIf(fp=fopen(”filel”,”w)=NULL)printf(”file cannot be opened n”);exit(1);elseprintf(”file opened for writing n”);12.2.3 关闭文件 程序对文件的读写操作完成后,必须关闭文件。这是因为对打开的磁盘文件进行写入时,若文件缓冲区的空间未被
20、写入的内容填满,这些内容将不会自动写入打开的文件中,从而导致内容丢失。只有对打开的文件进行关闭操作时,停留在文件缓冲区的内容才能写到磁盘文件上去,从而保证了文件的完整性。关闭标准文件用fclose()函数,函数说明如下:int fclose(FILE*stream);例如,fclose(fpl);它表示该函数将关闭FILE结构指针变量fpl对应的文件,并返回一个整数值。若成功地关闭了文件,则返回一个0值;否则返回一个非零值。12.2.4 文件的读写1.文件的字符读函数fgetc()这类函数每执行一次,只能读写文件中的一个字符。从磁盘文件读取字符的函数是fgetc(),其形式为:int fget
21、c(FILE*stream);例如:ch=fgetc(fp1);它表示函数从指针变量fp1指定的文件中读取一个字符并赋给变量ch,fgete()函数的 值就是该字符。这个fp1的值是用fopen()函数打开该文件时设定的。若执行fgetc()函数时遇到文件结束符EOF,则函数返回一个值-1给ch。注意,这个一l并不是函数读入的字符值,因为没有一个字符的ASCII码为-1,当系统判断出函数返回文件尾的信息EOF时,它就使函数的返回值为-l。2.文件的字符写函数fputc()将一个字符写入磁盘文件的函数是fputc(),其形式为:int fputc(int ch,FILE*stream);函数把字
22、符变量ch的值写入到由指针变量fp所指定的文件中。fputc()函数也有一个函数返回值。如果执行此函数成功就返回被输出的字符,否则就返回EOF。例12.1 编程实现读出磁盘文件datafile.txt中的内容,将它们显示在屏幕上。#include/*包含标准输入输出头文件*/main()FILE*fp;/*定义FILE结构指针变量*/char ch;if (fp=fopen(”datafile.txt”,”r”)=NULL)/*打开并测试文件*/printf(”file cannot be openedn”);exit(1);/*若文件打开不成功,退出*/while(ch=fgetc(fp)!
23、=EOF)/*读文件并测试是否文件尾*/fputc(ch,stdout);/*输出到标准设备文件(显示器)显示*/fclose(fp);/*关闭文件*/程序中使用了写文件函数fputc(),函数中使用的指针变量名为stdout,指示使用显示器设备文件,因而写文件的结果是将字符显示在显示器上。例12.2 编程完成:从键盘输入字符后,写入到磁盘文件datafilel.txt中。#include main()FILE*fpl;char strl;if(fpl=fopen(”datafilel.txt”,”w”)=NuLL)/*以只写方式打开文件,且测试*/printf(”file cannot be
24、 openedn”);exit(1);/*打开不成功退出*/while(strl=fgetc(stdin)!=n)/*从键盘输入并判断是否回车*/fpute(strl,fpl);/*写入到磁盘文件datafilel.txt中*/close(fpl);/*关闭文件*/该程序以只写方式打开文件datafilel.txt,在执行循环时,用fgetc()函数从标准设备文件stdin(即键盘)读入一个字符,再写到磁盘文件中。在键盘输入“回车”符后,退出循环。应该指出,文件读写函数fgetc()和fputc()在实际操作时是对文件缓冲区进行的,并非每一次读写一个字符都要启动磁盘操作。为了编程时书写方便,一
25、些C版本把fgetc()和fputc()函数定义为宏名getc()和putc(),即#define getc(fp)fgetc(fp)#define putc(ch,fp)fputc(ch,fp)因而getc()和fgetc()功能相同,putc()和fputc()相同。读者熟悉的getchar()和putchar()函数其实也是fgetc()和fputc()的宏,这时文件结构指针定义为标准输入stdin和标准输出stdout,即:#define getchar()fgetc(stdin)#define putchar(c)fputc(c,stdout)3.文件的字符串读函数 这类函数用于从文
26、件中读写字符串,其原型为:char*fgets(char*Str,int n,FILE*stream);其中,fgets()函数从指针stream指定的文件中读取n-1个字符,把它送到由指针str指向的字符数组中。例如:fgets(databuf,6,fp);可将fp指定的文件中的5个字符读到databuf内存区去。databuf可以是定义的字符数组,也可以是动态分配的内存区。fgets()读完指定的n-1个字符后返回。若在读入n-1个字符完成之前就遇到换行符n或文件结束符EOF,也将停止读入。但将遇到的换行符n也作为一个字符送入字符数组中。fgets()在读入字符串之后会自动添加一个串结束符
27、0,因此送入字符数组中的字符串(包括0在内)最多为n个字节。fgets()函数执行完后,返回一个指向该串的指针,即字符数组的首地址。如果读到文件尾或出错,则返回一个空值NULL。实际编程中,可以用ferror()函数或feof()函数来测定是读出出错还是到了文件尾。例12.3 编程完成:逐行读出datafile2.txt文件中的字符并显示出来。#include main()FILE*fp2;char buffer64;if(fp2=fopen(”datafile2.txt”,”r”)=NULL)/*以只读方式打开文件,且测试*/printf(”cant open filen”);exit(1)
28、;/*打开不成功退出*/while(!feof(fp2)/*测试文件是否结束*/if(fgets(buffer,64,fp2)!=NULL)/*读一行字符并测试是否为空*/printf(”%s”,buffer);/*显示该行字符*/fclose(fp2);/*关闭文件*/4.文件的字符串写函数fputs()它的原型为:char*fputs(char*Str,int n,FILE*stream);函数fputs()把由str指针指明的字符数组中的字符串写入由指针stream指定的文件中。该字符串以空字符0结束,但此字符将不写入到文件中去。str指向的字符串也可以用数组名代替,或用字符串常量代替。
29、例如,c=fputs(”computer0”,fp2);将把”computer”字符串写入由fp2指定的文件中去。该函数正确执行后,将返回写入的字符数。当出错时将返回-1。5.格式化读写函数 在实际应用中,应用程序有时需要按照规定的格式进行文件读写,这时可以利用C语言文件格式化读写函数fscanf()和fprintf()完成。fscanf()和fprintf()函数与格式化输入输出函数scanf()和printf()操作功能相似,不同之处是scarf()是从stdin标准输入设备(键盘)输入,printf()是向stdout标准输出设备(显示器)输出;fscanf()和fprintf()则是由
30、文件指针变量指定的文件输入或是向文件指针指定的文件输出。当文件指针变量定义为stdin和stdout时,这两个函数的功能就和scanf()和printf()相同了。格式化读写函数的调用格式如下:fscanf(FILE*stream,char*format,);fprintf(FILE*stream,char*format,);其中,char*format表示输入输出格式控制字符串,格式控制字符串的格式说明与scanf()数和printf()函数的格式说明完全相同;表示输入输出参量表。例如:fscanf(fp,”%s%d%f”,&va1l,&var2,&var3);完成按格式控制字符串sdf规定
31、的格式,从fp指定的文件中读取数据分别送入变量var1、var2、var3中。例12.4 从键盘输入字符信息及数组信息后,用格式化方式写入磁盘文件中。#include main()FILE*fp6;char str20;int age,i;float sum;if(fp6=fopen(”datafile5.txt”,”w”)=NULL)/*打开文件*/printf(”File connot be openedn”);exit(1);printf(”type str:”);for(i=0;i1)/*输入字符长度大于1则循环*/printf(fp6,”%s%d%f”,str,age,sum);/*
32、写入磁盘文件*/printf(”type str,age,sum:”);scanf(”%s%d%f”,str,&age,&sum);/*输入姓名、年龄和总成绩*/fclose(fp6);/*关闭文件*/程序打开文件成功后,通过循环将多个数据以规定的格式写入磁盘文件中。一旦输入的字符长度不大于l,则退出循环,结束程序运行。12.2.5 文件的随机读写 在C语言的实际应用中,常常希望能直接读写文件中的某一个数据项,而不是按文件的物理顺序逐个地读写数据项。这种可以任意指定读写位置的文件操作,称为随机读写。从上面的叙述可知,只要能移动文件指针到所需的地方,就可实现文件的随机读写。C语言提供了多个函数以
33、实现随机操作。1文件指针定位函数 实现随机文件读写操作,首先必须解决定位问题。C语言提供的文件指针定位函数有三个,其函数调用形式分别为:在C语言的实际应用中,常常希望能直接读写文件中的某一个数据项,而不是按文件的物理顺序逐个地读写数据项。这种可以任意指定读写位置的文件操作,称为随机读写。从上面的叙述可知,只要能移动文件指针到所需的地方,就可实现文件的随机读写。C语言提供了多个函数以实现随机操作。1.文件指针定位函数 实现随机文件读写操作,首先必须解决定位问题。C语言提供的文件指针定位函数有三个,其函数调用形式分别为:int fseek(FILE*stream,long offset,int o
34、rigin);long ftell(FILE*stream);void rewind(FILE*stream);这里fseek()函数的作用是使文件指针移动到所需的位置。stream指定需要操作的文件;origin指明以什么地方为基准进行指针移动,起点位置有如表12.2所示的几种选择:表12.2 指针起始位置及其代表符号 起始点具体位置 符号代表 数字代表 文件的开头 SEEK_SET 0 文件指针现行位置 SEEK_CUR 1 文件尾 SEEK_END 2 offset是位移量,是以origin为基准指针向前或向后移动的字节数。所谓向前是指从文件开头向文件尾移动的方向;向后则反之。位移量的值
35、如果为负,表示指针向后移动。位移量应为long型数据,这样当文件的长度很长时(例如大于64 K),位移量仍在long型数据表示范围之内。例如:fseek(fp,10L,SEEK_SET);其作用是把文件指针从文件开头移到第10个字节处。下面的写法与其功能是一致的:fseek(fp,10L,0);例如:fseek(fp,-20L,SEEK_END);它把文件指针从文件尾向前移动20个字节。例如:fseek(fp,-5L,1);函数将把文件指针从现行位置往回移动5个字节。若fseek()函数调用成功,返回值为0;否则返回一个非零值。函数ftell()用于得到文件指针离开文件起点的偏移量(即偏移的字
36、节数)如果函数调用出错(例如该文件不存在),则函数的返回值是-l。rewind()函数用于把文件指针移到文件的开头。移动成功时,返回值为0,否则返回一个非零值。利用fseek()函数控制文件位置后,也可使用前述文件操作函数进行顺序读写,但顺序读写的起始位置不一定是从头开始,可以通过fseek()函数设定。例12.5 用fseek()函数完成定位读操作。#include main()FILE*fp7;char buf32;if(fp7=fopen(”datafile7.dat”,”rb”)=NULL)/*打开文件*/printf(”File connot be openedn”);exit(1)
37、;fseek(fp7,64 L,SEEK_SET);/*定位文件指针*/fgets(buf,32,fp7);/*读字符串送入buf数组中*/fclose(fp7);/*关闭文件*/该程序在文件datafile7.dat的第64个字节处开始,用顺序读函数fgets()读出一行字符。2.文件随机读写函数 C语言标准文件随机读写函数分别为fread()和fwrite(),函数原型为:int fread(void*ptr,int size,int count,FILE*stream);int fwrite(void*ptr,int size,int count,FILE*stream);其中:ptr指
38、针指向内存缓冲区,count为数据项个数,每个数据项的长度为size个字节。stream是文件指针变量。这两个函数实际上是按数据项(即数据块)进行操作,通过它们可以方便地对程序中的数组、结构体数据进行整体输入输出。fread()函数从文件指针变量指定的文件中,读取count个数据项,存入由ptr指定的内存缓冲区中。fread()函数依据文件指针指定的位置读取,该指针也随着读取的字节数向后移动,最后移动结束的位置等于实际读出的字节数。函数执行结束后,将返回实际读出的数据项项数,这个项数可能不等于count,因为若文件中没有足够的数据项或读过程中出错,均会导致返回的数据项项数少于设定的项数。当返回
39、的项数少于设定的数目时,可以用feof()或ferror()函数进行检查,判断是文件尾还是读出出错。ferror()函数将在下一节中介绍。fwrite()函数从由ptr指定的内存缓冲区取出count个数据项,写入文件指针变量指向的文件中。执行该操作后,文件指针也将向后移动,移动的字节数等于写入文件的字节数。函数操作完成后,也将返回写入的数据项项数。当返回值小于设置的项数时,可能是缓冲区的数据不够,或是写入出错。例如:fwrite(buffer,50,64,fp);表示从数组名buffer所代表的数组起始地址开始,每次输出长度为50个字节的数据项,共输出64个数据项,将它们写入到由fp指定的磁盘
40、文件中。若写入成功,函数返回值为64。注意,用fread()和fwrite()函数进行读写时,必须采用二进制。例12.612.6 编写程序,将一个浮点数写入磁盘文件后,再将其读出显示出来。#include main()FILE,*fp8,fp9float fdata1=25.68,fdata2;if(fp8=fopen(”datafile8”,”wb”)=NULL)/*打开文件*printf(”cannot open the file.n”);exit(1);/*出错退出*/fwrite(&fdatal,sizeof(float),1,fp8);/*写文件*/fclose(fp8);/*关闭文
41、件*/if(fp9=fopen(”datafile8”,”rb”)=NULL)/*打开文件*/printf(”cannot open the file.n”);exit(1);/*出错退出*/12.2.6 文件的错误检测 1.ferror函数 在各种输入输出函数(如putc,getc,fscanf,fprintf等)被调用时,如果出现错误,除了被调函数返回值有所反映外,还可以用ferror函数检查。它的调用形式为 ferrorferror(fpfp);如ferror返回值为0,表示未出错;如返回一个非0值,表示出错。值得注意的是:对同一个文件每一次调用输入输出函数,都会产生一个新的ferror函数值,因此,应当在调用一个输入输出函数后立即检查ferror函数的值,不然信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0。2.clearerr函数一般调用形式:clearerclearer(fp);功能:使fp指向的文件错误标志和文件结束标志置0。说明:只要出现输入输出函数的错误标志,就一直保留,直到对同一文件调用clearerr函数或rewind函数,或者其他任何一个输入输出函数。