C语言程序设计基础主讲教师:代祖华主要参考书目《C程序设计》(第二版)及配套的程序设计题解与设计指导,谭浩强著,清华大学出版社。《从问题到程序—程序设计与C语言引论》裘宗燕著,机械工业出版社。《程序设计基础》及配套的程序设计题解与设计指导(第二版),吴文虎编著,清华大学出版社。第八章文件在程序运行时,程序本身和数据一般都存放在内存中。当程序运行结束后,存放在内存中的数据被释放。如果需要长期保存程序运行所需的原始数据,或程序运行产生的结果,就必须以文件形式存储到外部存储介质上。12.1C语言文件概述12.2文件的打开与关闭12.3文件的读写操作12.4位置指针与文件定位12.5出错检测8.1C语言文件概述一.文件与文件名文件是指存放在外部存储介质上的数据集合。为标识一个文件,每个文件都必须有一个文件名,其一般结构为:主文件名[.扩展名]文件命名规则,遵循操作系统的约定。二.文件分类可以从不同的角度对文件进行分类:1.根据文件的内容,可分为程序文件和数据文件,程序文件又可分为源文件、目标文件和可执行文件。2.根据文件的组织形式,可分为顺序存取文件和随机存取文件。3.根据文件的存储形式,可分为文本文件(ASCII码文件)和二进制文件。文本文件(ASCII码文件)的每1个字节存储1个字符,因而便于对字符进行逐个处理。但一般占用存储空间较多,而且要花费转换时间(二进制与ASCII码之间的转换)。二进制文件是把内存中的数据,原样输出到磁盘文件中。可以节省存储空间和转换时间,但1个字节并不对应1个字符,不能直接输出字符形式。三.读文件与写文件所谓读文件是指,将磁盘文件中的数据传送到计算机内存的操作。所谓写文件是指,从计算机内存向磁盘文件中传送数据的操作。四.构成文件的基本单元与流式文件C语言将文件看作是由一个一个的字符(ASCII码文件)或字节(二进制文件)组成的。将这种文件称为流式文件。而在其它高级语言中,组成文件的基本单位是记录,对文件操作的基本单位也是记录。五.文件类型FILE1.系统给每个打开的文件在内存中开辟一个区域,用于存放文件的有关信息(如文件名、文件位置等)。这些信息保存在一个结构类型变量中,该结构类型由系统定义、取名为FILE。(该结构类型信息见教材288页表8.3)注意:结构类型名“FILE”必须大写。2、缓冲文件系统借助FILE结构类型对文件进行管理,利用文件指针读写文件。每当程序成功打开一个文件,系统就在内存建立一个与该文件对应的FILE结构体变量,并返回该变量的指针(地址)。3、文件型指针变量的定义FILE*指针变量标识符;如:FILE*fp;定义一个指针变量fp,用以保存已打开文件所对应的FILE结构在内存的地址,此后用户程序就可用此指针来实现对指定文件的存取操作。如果有N个文件,一般应设N个指针变量,使它们分别指向N个文件,以实现对文件的访问。六.缓冲文件系统所谓缓冲文件系统是指,系统自动地在内存区为每个正在使用的文件开辟一个缓冲区。从内存向磁盘输出数据时,必须首先输出到缓冲区中。待缓冲区装满后,再一起输出到磁盘文件中。从磁盘文件向内存读入数据时,则正好相反:首先将一批数据读入到缓冲区中,再从缓冲区中将数据逐个送到程序数据区。程序数据区输出文件缓冲区输入输入文件缓冲区输出输入磁盘内存输出其原理图如下:非缓冲文件系统:不使用缓冲区的磁盘文件系统。七、缓冲文件系统文件操作的四个基本步骤:1.文件类型指针变量的定义2.打开文件3.文件的读或写的操作4.文件的关闭操作注:对文件操作的库函数,函数原型均在头文件stdio.h中。后续不再赘述。注:后续主要介绍缓冲文件系统的文件操作函数。8.2文件的打开与关闭对文件进行操作之前,必须先打开该文件;使用结束后,应立即关闭,以免数据丢失。C语言规定了标准输入输出函数库,用fopen()函数打开一个文件,用fclose()函数关闭一个文件。一、文件的打开──fopen()函数1.用法:FILE*fopen(文件名“,操作方式);2.功能:返回一个指向指定文件的指针。(1)“文件名”是指要打开(或创建)的文件名。如果使用字符数组(或字符指针),则不使用双引号。(2)“操作方式”见教材289页表8.4所示。例如,FILE*fp;fp=fopen(data.99,r);3.说明(1)如果不能实现打开指定文件的操作,则fopen()函数返回一个空指针NULL(其值在头文件stdio.h中被定义为0)。为增强程序的可靠性,常用下面的方法打开一个文件:if((fp=fopen(文件名,操作方式))==NULL){printf(cannotopenthisfile\n);exit(0);}(2)“r(b)+”与“a(b)+”的区别:使用前者打开文件时,读写位置指针指向文件头;使用后者时,读写指针指向文件尾。(3)使用文本文件向计算机系统输入数据时,系统自动将回车换行符转换成一个换行符;在输出时,将换行符转换成回车和换行两个字符。使用二进制文件时,内存中的数据形式与数据文件中的形式完全一样,就不再进行转换。(5)在程序开始运行时,系统自动打开三个标准文件,并分别定义了文件指针1)标准输入文件——stdin:指向终端输入(一般为键盘)。如果程序中指定要从stdin所指的文件输入数据,就是从终端键盘上输入数据。2)标准输出文件——stdout:指向终端输出(一般为显示器)。3)标准错误文件——stderr:指向终端标准错误输出(一般为显示器)。二、文件的关闭──fcolse()函数1.用法:intfclose(FILE*文件指针);2.功能:关闭“文件指针”所指向的文件。如果正常关闭了文件,则函数返回值为0;否则,返回值为非0。例如fclose(fp);/*关闭fp所指向的文件*/8.3文件的读写操作文件打开之后,就可以对它进行读与写的操作了。一、读/写文件中的一个字符二、读/写一个字符串三、读/写一个数据块四、对文件进行格式化读/写1.文件写入字符函数:fputc函数返回值:输出成功,返回值就是输出的字符;输出失败,返回一个EOF(值为-1)。功能:把一个字符ch写到fp指向的磁盘文件上去。函数原型:intfputc(intch,FILE*fp);一、读/写文件中的一个字符例:FILE*fp;charch=’A’;…fputc(ch,fp)函数原型:2.读文件字符函数:fgetcfp是指向所读文件指针变量intfgetc(FILE*fp);函数功能:从文件指针fp指向的文件当前位置(位置指针)读出一个字符,然后文件位置指针自动后移,指向文件中的下一个字符,返回值为读入的字符.若遇到文件结束符,则返回结束符EOF(-1).例:ch=fgetc(fp);例:见教材293页例8.31、库函数fputs()──向指定文件输出一个字符串1)函数原型:intfputs(字符串,文件指针);其中“字符串”可以是一个字符串常量,或字符数组名,或字符指针变量名。2)功能:向指定文件输出一个字符串,同时将读写位置指针向前移动strlength(字符串长度)个字节。如果输出成功,则函数返回值为0;否则,为非0值。2、库函数fgets()──从文件中读一个字符串1)函数原型:char*fgets(指针,串长度+1,文件指针);2)功能:从指定文件中读入一个字符串,存入“字符数组/指针”中,并在尾端自动加一个结束标志'\0';同时,将读写位置指针向前移动strlength(字符串长度)个字节。如果在读入规定长度之前遇到文件尾EOF或换行符,读入即结束。二、读/写一个字符串──fgets()和fputs()三、读/写一个数据块──fread()和fwrite()实际应用中,常常要求1次读/写1个数据块。为此,ANSIC标准设置了fread()和fwrite()函数。fread()和fwrite()函数,一般用于二进制文件的处理。1.函数原型intfread(void*buffer,intsize,intcount,FILE*fp);intfwrite(void*buffer,intsize,intcount,FILE*fp);2.功能:fread()──从fp所指向文件的当前位置开始,一次读入size个字节,重复count次,并将读入的数据存放到从buffer开始的内存中;同时,将读写位置指针向前移动size*count个字节。其中,buffer是存放读入数据的起始地址。fwrite()──从buffer开始,一次输出size个字节,重复count次,并将输出的数据存放到fp所指向的文件中;同时,将读写位置指针向前移动size*count个字节。其中,buffer是要输出数据在内存中的起始地址。如果调用fread()或fwrite()成功,则函数返回值等于count。例题见教材296页例8.5四、对文件进行格式化读/写──fscanf()和fprintf()函数与scanf()和printf()函数的功能相似,区别在于:fscanf()和fprintf()函数的操作对象是指定文件,而scanf()和printf()函数的操作对象是标准输入(stdin)输出(stdout)文件。intfscanf(文件指针,格式符“,输入变量首地址表);intfprintf(文件指针,格式符“,输出参量表);例如,inti=3;floatf=9.80;fprintf(fp,%2d,%6.2f,i,f);......fprintf()函数的作用是,将变量i按%2d格式、变量f按%6.2f格式,以逗号作分隔符,输出到fp所指向的文件中:□3,□□9.80(□表示1个空格)。8.4位置指针与文件定位文件中有一个读写位置指针,指向当前的读写位置。每次读写1个(或1组)数据后,系统自动将位置指针移动到下一个读写位置上。如果想改变系统这种读写规律,可使用以下文件定位函数。一、位置指针复位函数rewind()1.用法:intrewind(文件指针);2.功能:使文件的位置指针返回到文件头。二、随机读写与fseek()函数对于流式文件,既可以顺序读写,也可随机读写,关键在于控制文件的位置指针。所谓顺序读写是指,读写完当前数据后,系统自动将文件的位置指针移动到下一个读写位置上。所谓随机读写是指,读写完当前数据后,可通过调用fseek()函数,将位置指针移动到文件中任何一个地方。1.函数原型:intfseek(文件指针,位移量,参照点);2.功能:将指定文件的位置指针,从参照点开始,移动指定的字节数。(1)参照点:用0(文件头)、1(当前位置)和2(文件尾)表示。在ANSIC标准中,还规定了下面的名字:SEEK_SET──文件头,SEEK_CUR──当前位置,SEEK_END──文件尾(2)位移量:以参照点为起点,向前(当位移量0时)或后(当位移量0时)移动的字节数。在ANSIC标准中,要求位移量为longint型数据。fseek()函数一般用于二进制文件。三、返回文件当前位置的函数ftell()由于文件的位置指针可以任意移动,也经常移动,往往容易迷失当前位置,ftell()就可以解决这个问题。1.函数原型:longftell(文件指针);2.功能:返回文件位置指针的当前位置(用相对于文件头的位移量表示)。如果返回值为-1L,则表明调用出错。例如:offset=ftell(fp);if(offset==-1L)printf(“ftell()error\n”);8.5文件检测函数一、文件结束检测函数feof函数原型:intfeof(FILE*fp);函数功能:判断fp指向的文件是否处于文件结束位置,如文件结束,则返回值为1,否则为0。二、ferror()函数在调用输入输出库函数时,如果出错,除了函数返回值有所反映外,也可利用ferror()函数来检测。1.函数原型:intferror(文件指针);2.功能:如果函数返回值为0,表示未出错;如果返回一个非0值,表示出错。(1)对同一文件,每次调用输入输出函数均产生一个新的ferror()函