1、第11章 文件类型 第第11章章 文件类型文件类型 11.1 文件类型与文件指针文件类型与文件指针 11.2 文件的打开与关闭文件的打开与关闭 11.3 文件的读写与建立文件的读写与建立 11.4 文件辅助操作文件辅助操作 11.5 程序设计举例程序设计举例 第11章 文件类型 11.1 文件类型与文件指针文件类型与文件指针 1.文本文件和二进制文件文本文件和二进制文件 C语言文件把数据看作是一连串的字符(字节)。C语言文件是一个字符(字节)的序列,是一字符流或字节流,是一种流式文件。根据数据的组织形式,可分为文本文件和二进制文件。第11章 文件类型 文本文件又称为ASCII文件,每一个字节中
2、存放一个ASCII代码,代表一个字符。例如,一个整数123,若用ASCII文件存放,占3个字节的存储单元,1、2、3各用一个字节存储。而1、2、3的ASCII码分别为49、50、51,故123用ASCII文件存放时,存放形式为001100010011001000110011。二进制文件是直接用数据的二进制形式存放。例如,对整数123,二进制为0000000001111011,用二进制 文 件 存 放,需 2 个 字 节,存 放 形 式 为0000000001111011。第11章 文件类型 2.缓冲文件系统和非缓冲文件系统缓冲文件系统和非缓冲文件系统 在缓冲文件系统中,系统自动在内存中为每个正
3、在使用的文件开辟一个缓冲区,文件的存取都是通过缓冲区进行的。缓冲区相当于一个中转站,它的大小由具体的C版本规定,一般为512字节。缓冲文件系统原来用于处理文本文件。在非缓冲文件系统中,系统不为所打开的文件自动开辟缓冲区,缓冲区的开辟由程序完成。非缓冲文件系统原来用于处理二进制文件。ANSI C不再采用非缓冲文件系统,而只采用缓冲文件系统,在处理二进制文件时,也通过缓冲文件系统进行。ANSI C通过扩充缓冲文件系统,使缓冲文件系统既能处理文本文件,又能处理二进制文件。第11章 文件类型 3.内部文件和外部文件内部文件和外部文件 存放在外部介质上的文件称为外部文件,通过文件名标识。C程序中的文件称
4、为内部文件,用文件指针来描述。程序中要实现对文件的处理,先必须在内部文件与外部文件之间建立联系,打开文件;然后方可对文件进行操作。文件最基本的操作是读写操作;操作完成应当切断内部文件与外部文件之间的联系,关闭文件。对文件进行的所有操作通过C编译系统提供的标准函数完成,这些函数的信息包含在头文件“stdio.h”中。第11章 文件类型 11.1.2 文件类型文件类型 在缓冲文件系统中,系统为每个被使用的文件都在内存中开辟一个区域,用来存放文件名、文件状态、缓冲区状态及文件当前位置等信息,这些信息保存在一个结构体变量中。文件类型是一个特殊的结构体类型,一般命名为FILE。用户可以直接使用FILE来
5、定义文件类型变量,存放要处理的文件的基本信息。各种C编译系统的FILE定义可以不同,但均包含进行文件处理所需的基本信息。第11章 文件类型 下面是TURBO C中对FILE的定义:typedef struct short level;unsigned flags;char fd;unsigned char hold;short bsize;unsigned char *buffer;unsigned char *curp;unsigned istemp;short token;FILE;第11章 文件类型 11.1.3 文件指针变量文件指针变量 对文件的描述,往往通过指向文件的文件指针变量来进
6、行。文件指针变量定义的形式为:FILE *文件指针变量;例如:FILE *fp,*fpa10;定义了文件指针变量fp和文件指针变量数组fpa。文件指针变量fp及文件指针变量数组fpa的每个分量可以指向一个文件的信息。第11章 文件类型 11.2 文件的打开与关闭文件的打开与关闭 11.2.1 文件的打开文件的打开 文件的打开用fopen()函数完成,调用方式通常为:fp=fopen(文件名,文件使用方式);第11章 文件类型 文件使用方式共有 12 种,用特定字符形成的字符串来描述。(1)r方式,以只读方式打开文本文件。这时从文件中读数据到内存,故要求文件已经存在。用r方式打开的文件只能读,不
7、能同时写。(2)w方式,以只写方式打开文本文件。这时将内存中的数据写入到磁盘文件中。若文件不存在,建立新文件;若文件存在,则刷新文件,重新建立。用w方式打开的文件只能写,不能同时读。第11章 文件类型 (3)a方式,为文本文件的追加方式。用于向已存在的文件尾部追加新的数据,而文件中原来的数据不被破坏。(4)r+、w+、a+方式,打开的文本文件既能读又能同时写。r+方式:在读的同时可以进行写。读写位置指针在头部,若原来存在此文件,则以覆盖方式写。w+方式:在写的同时可以进行读。由于打开文件时,文件原来的内容被刷新,一般不要在打开文件后立即读文件。a+:在追加的同时可以进行读。读文件时,从文件首部
8、开始;写文件时,在文件尾部追加。第11章 文件类型 (5)rb、wb、ab、rb+、wb+、ab+是使用二进制文件相应的六种方式。打开文件可得到三个信息:要访问的文件名。使用文件的方式。哪一个指针变量用于指向被打开的文件。打开成功,返回文件指针(文件信息区的起始地址);不能打开,返回空指针。第11章 文件类型 例如:例如:(1)fp=fopen(student.dat,w);以只写方式打开当前盘当前目录下的文本文件中的学生数据文件,用户可将数据写入此磁盘文件中。(2)fp=fopen(c:cjcjc.dat,student.dat,r);以只读方式打开C盘成绩子目录下C语言成绩文件,用户可将文
9、件中数据读出来。但此文件必须存在,否则会出错。第11章 文件类型 (3)fp=fopen(PRG,ab+);打开二进制文件PRG,在读的同时也可以写。为确保文件的读写操作,对文件是否已正常打开往往加上if语句进行控制。例如:if(fp=fopen(student.dat,w)=NULL)printf(不能打开文件!);exit(0);第11章 文件类型 说明:说明:(1)不是所有编译系统均提供以上 12 种文件使用方式。(2)用r、rb方式打开的文件必须已经存在。(3)用w、wb方式打开的文件,可以存在也可以不存在。不存在时,则新建文件;存在时,重新建立,原文件内容不被保留。(4)在读写文本文
10、件时,对回车换行符要进行转换,读时回车换行符转换成换行符,写时回车换行符转换成回车、换行两个字符。对二进制文件,不进行这种转换。第11章 文件类型 (5)程序运行时,系统自动打开标准输入stdin、标准输出stdout、标准出错输出stderr三个标准文件。stdin、stdout、stderr由系统自动定义,可直接使用。(6)标准设备文件可与普通文件一样操作,但将产生特殊效果。如写到打印机,将在程序中实现打印输出控制。第11章 文件类型 11.2.2 文件的关闭文件的关闭 文件在使用完后,应及时关闭。文件的关闭用fclose()函数完成,调用方式为:fclose(文件指针变量);关闭文件将使
11、文件指针变量与文件名脱钩,即指针变量不再指向该文件。文件关闭后不能再用该指针变量对文件进行操作,该指针变量可再指向其它文件。顺利执行了关闭操作,将返回函数值0。如返回一个非0值,则表示文件关闭出错。第11章 文件类型 11.3 文件的读写与建立文件的读写与建立 11.3.1 字符级数据的读和写字符级数据的读和写 1.字符级数据的读字符级数据的读 函数原型:int fgetc(FILE *fp);功能:从文件指针fp所指向的文件中读取一个字节的代码值(字符),作为函数的返回值。正常情况下为一个字符,读到文件尾或出错时为EOF(-1)。第11章 文件类型 说明:(1)读完一字节数据后,文件指针自动
12、后移。(2)getc和fgetc是等价的宏。(3)若文件指针为stdin,则fgetc(stdin)功能与getchar()等价。第11章 文件类型 2.字符级数据的写字符级数据的写 函数原型:int fputc(int ch,FILE*fp);功能:将ch写入文件指针fp所指向的文件中。写入成功返回字符值,不成功返回值EOF。说明:(1)写入数据前,文件指针自动后移。(2)puttc和fputc是等价的宏。(3)若文件指针为stdout,则fputc(stdout)功能与puttchar()等价。(4)文件的建立通过写操作完成。第11章 文件类型 11.3.2 字级数据的读和写字级数据的读和
13、写 1.字级数据的读字级数据的读 函数原型:int getw(FILE *fp);功能:从文件指针fp所指文件中读一个字的数据(整数),并以它作为函数的返回值。说明:非标准C所提供函数。第11章 文件类型 2.字节数据的写字节数据的写 函数原型:int putw(int w,FILE *fp);功能:写一个字的数据(整数)到文件指针fp所指的文件中,并以它作为函数的返回值。说明:非标准C所提供函数。第11章 文件类型 11.3.3 字符串级数据的读和写字符串级数据的读和写 1.字符串数据的读字符串数据的读 函数原型:char *fgets(char *str,int len,FILE *fp)
14、;功能:功能:从文件指针fp所指的文件中读入一个长度为len-1的字符串,送入到str所指内存地址中。返回值为str的首地址,若读到文件尾或出错,则返回值为NULL。第11章 文件类型 说明:(1)字符串读入后在最后加结尾符0。(2)将读到的回车符作为字符存储。这点与gets()函数不同,gets()把读到的回车符转换成结尾符。(3)字符串数据的读和写亦称“行处理”。第11章 文件类型 2.字符串数据的写字符串数据的写 函数原型:int fputs(char *str,FILE *fp);功能:将str指针所指字符串写入到文件指针fp所指文件中。若该函数成功调用,返回函数值0,否则返回函数值非
15、0。第11章 文件类型 11.3.4 数据块数据的读和写数据块数据的读和写 1.数据块数据的读数据块数据的读 函数原型:unsigned fread(void*buffer,unsigned size,unsigned count,FILE*fp);功能:从文件指针fp所指的文件中读取count个大小为size字节的数据块到buffer指针所指的内存中。读到的数据可能含有各种不同的类型。若该函数成功调用,返回count的值。第11章 文件类型 例如:int a100;fread(a,2,100,fp);/*从fp读取100个大小为2字节的数据块(整数)到数组a中*/第11章 文件类型 2.数据
16、块数据的写数据块数据的写 函数原型:unsigned fwrite(void*buffer,unsigned size,unsigned count,FILE*fp);功能:向文件指针fp所指的文件写入由buffer指针所标识的count个大小为size字节的数据块。若该函数成功调用,返回count的值。例如:int a100;fwrite(a,2,100,fp);/*将整个数组a写入文件fp中*/第11章 文件类型 11.3.5 格式化数据的读和写格式化数据的读和写 1格式化读格式化读函数原型:函数原型:int fscanf(FILE*fp,格式字串,地址表);功能:按指定格式从文件fp中读
17、取数据至指定地址。例如:int i,j;float f;fscanf(fp,%d%d%f,&i,&j,&f);/*从fp中按指定格式读取数据至i、j、f中*/第11章 文件类型 2格式化写 函数原型:int fprintf(FILE*fp,格式字串,变量表);功能:按指定格式将给定数据写入文件fp中。使用fscanf()和fprintf()函数对磁盘文件进行读和写相当方便,但是输入时需将ASCII码转换为二进制,输出时需将二进制转换成ASCII码,费时间,故一般较少采用,而是使用fread()和fwrite()函数。第11章 文件类型 11.3.6 文件的建立步骤文件的建立步骤 对文件操作前必
18、须打开文件,文件打开后才可进行读写操作,操作完成应关闭文件。文件的建立步骤如下:(1)以写方式打开文件。(2)将数据写入文件,多个数据反复写入。(3)写完数据关闭文件。第11章 文件类型 例例 11-1 定义一个函数,建立存放26个英文小写字母的文件LF.DAT。void creatfile()char l;FILE *fp;if(fp=fopen(LF.DAT,w)=NULL)/*打开文件*/printf(不能打开文件!);exit(0);for(l=a;l=z;l+)/*写入数据*/fputc(l,fp);fclose(fp);/*关闭文件*/第11章 文件类型 例例 11-2 定义一个函
19、数,建立存放某班50个同学姓名、C语言成绩的数据文件CCJ.DAT,原始数据由数组参数传入。void creatfile(float x)int i;FILE *fp;if(fp=fopen(CCJ.DAT,wb)=NULL)/*打开文件*/printf(不能打开文件!);exit(0);for(i=0;i=50;i+)/*写入数据*/fwrite(x+i,4,1,fp);fclose(fp);/*关闭文件*/第11章 文件类型 写入数据也可以整体一次完成:fwrite(x,4,50,fp);(1)文件的建立在操作系统下可通过改向操作完成。(2)数据源文件也可通过任何字处理软件建立。(3)执行
20、一个向打印机写的操作,可在程序中实现数据的打印输出。例如:fp=fopen(PRN:,w);fputs(HUNAN COMPUTER,fp);/*打印输出HUNAN COMPUTER*/打印输出也可直接使用系统提供的打印机文件指针stdprn。第11章 文件类型 11.3.7 文件的读取控制文件的读取控制 是不是处于文件尾部,可用文件结尾标志EOF来判断,还可用feof()函数来判断,即 (1)while(fgetc(fp)!=EOF)读取数据 (2)while(!feof(fp)读取数据 对于二进制文件,由于最后一个数据可能为1(EOF),因此最好用feof()函数控制读取。当然,读文件前应
21、先打开文件,读完数据后应该关闭文件。第11章 文件类型 例例11-3 从上例建立的文件CCJ.DAT中读出学生的C语言成绩,求出每个学生与平均成绩之差。/*程序11-3,求每个学生与平均成绩之差*/struct stchar *name;float cj;C200;/*假定学生人数不超过200人*/main()int i=0,n;float sum=0,av;float sav200;/*与平均成绩之差*/FILE *fp;第11章 文件类型 FILE *fp;if(fp=fopen(CCJ.DAT,rb)=NULL)/*打开文件*/printf(不能打开文件!);exit(0);while(
22、!feof(fp)/*读数据,同时进行累加*/fread(c+i,6,1,fp);sum+=ci.cj;i+;n=i;av=sum/n;/*求平均成绩*/for(i=0;in;i+)/*求与平均成绩之差并输出*/savi=ci.cjav;printf(%s,%6.1f,%6.1fn,ci.name,ci.cj,savi);第11章 文件类型 11.4 文件辅助操作文件辅助操作 1.反绕函数反绕函数函数原型:void rewind(FILE *fp);功能:使文件的读写位置指针返回文件开头。第11章 文件类型 2.随机定位函数随机定位函数 函数原型:int fseek(FILE *fp,long
23、 int numbytes,int origin);功能功能:将文件的位置指针移动numbytes个字节,numbytes为正数表示后移,为负数表示前移。其中移动的开始位置由origin确定,origin的值可以为0、1、2,或SEEK-SET、SEEK-CUR、SEEK-END,分别代表“文件开头”、“当前位置”、“文件末尾”三个特殊位置。第11章 文件类型 例如:例如:(1)fseek(fp,100l,0);/*将文件的位置指针移动到离文件开头100个字节处*/(2)fseek(fp,50l,1);/*将文件的位置指针向前移动50个字节处*/(3)fseek(fp,-10l,2);/*将文
24、件的位置指针向后移10个字节处*/利用随机定位函数实现对文件的随机读写。第11章 文件类型 3.求当前读写位置函数求当前读写位置函数 函数原型:long int ftell(FILE *fp);功能:得到文件的当前读写位置指针,用相对于文件开头的位移量来表示。若出现调用错误,返回值为-1。第11章 文件类型 4.出错检测函数出错检测函数 函数原型:int ferror(FILE *fp);功能:检查文件中各种输入输出函数调用是否出错。若得到的函数值为0,表示未出错;得到的函数值非0,表示出错。调用fopen()函数时,ferror初值自动置0。第11章 文件类型 5.初始化清零函数初始化清零函
25、数 函数原型:void clearerr(FILE *fp);功能:清除文件错误标志和文件结束,将文件错误标志和文件结束标志置0。输入输出函数调用出错后,出错标志一直保留,直到对同一文件调用clearerr()函数、rewind()函数或任一输入输出函数。第11章 文件类型 11.5 程序设计举例程序设计举例 例例 11-4 从键盘输入若干字符,存入某磁盘文件中,然后从文件中读取数据打印输出。/*程序11-4,输入若干字符至文件,并打印输出*/main()char ch,*fname;FILE *fp,*pp;scanf(%s,fname);/*输入磁盘文件名*/*建立文件*/if(fp=fo
26、pen(fname,w)=NULL)printf(文件不能打开!);第11章 文件类型 exit(0);ch=getchar();/*从键盘读数据并写入文件fp*/while(ch!=n)fputc(ch,fp);ch=getchar();fclose(fp);/*从刚建立的磁盘文件中读取数据,并打印输出*/if(fp=fopen(fname,r)=NULL)/*打开数据文件*/printf(数据文件不能打开!);exit(0);第11章 文件类型 if(pp=fopen(PRN:,w)=NULL)printf(打印机没能连接!);exit(0);ch=fgetc(fp);while(!feo
27、f(fp)fprintf(pp,%6c,ch);ch=fgetc(fp);fclose(fp);fclose(pp);第11章 文件类型 例例 11-5 学生信息包含有学号、姓名、年龄、成绩及住址,从键盘输入n个学生的这些信息,然后存入一个磁盘文件STUDENT.DAT中。算法提示:(1)学生信息含有不同类型的数据,故用结构体数组描述。(2)为方便使用,文件的建立用函数完成,学生信息写入文件时用fwrite()函数进行。第11章 文件类型 程序如下:/*程序11-5,建立学生信息文件*/define SIZE 200struct studentint num;char *name;int ag
28、e;float score;char *addr;stud SIZE;/*学生数组*/int n;/*学生人数*/第11章 文件类型 void save()/*建立文件STUDENT.DAT*/FILE *fp;int i;if(fp=fopen(STUDENT.DAT,wb)=NULL)printf(不能建立文件!);exit(0);for(i=0;in;i+)if(fwrite(&studi,sizeof(struct student),1,fp)!=1)printf(文件不能写!n);exit(0);第11章 文件类型 fclose(fp);main()int i;scanf(%d,&n
29、);for(i=0;in;i+)/*从键盘输入数据*/scanf(%d%s%d%f%s,&stud i.mum,stud i.name,&stud i.age,&stud i.score,stud i.addr);save();/*调用函数建立文件*/第11章 文件类型 例11-6 文件auto.dat存放了某道路同一时间各路段的车流信息,内容如下表。从文件中读取数据,计算各路段的车流量。车车 型型路段路段1路段路段2路段路段3路段路段4BUS1001208098JEEP50997090TRUCK76234200190CAR234400365380MOTO800650700740第11章 文件
30、类型/*例11-6,分段车流量计算*/main()struct at char *name;int num4;auto5;/*原始数据*/FILE*fp;int i,j;int vehicle4;/*输出数组*/if(fp=fopen(auto.dat,rb)=NULL)/*打开文件*/printf(不能打开文件!);exit(0);第11章 文件类型 i=0;while(!feof(fp)/*读数据*/fread(auto+i,10,1,fp);i+;for(i=0;i4;i+)/*计算车分段流量*/vehicle4=0;for(j=0;j5;j+)vehiclei+=autoj.numi;
31、printf(路段1 路段2 路段3 路段4n);for(i=0;i4;i+)/*输出*/printf(%8d,vehiclei);第11章 文件类型 运行结果:路段1 路段2 路段3 路段41260 1503 1415 1538 第11章 文件类型 例11-7 编写类似DOS的拷贝命令的文件复制程序。算法提示:(1)进行文件复制时需给出源文件与目标文件,程序中利用主函数的参数通过命令行获得。(2)进行文件复制时反复从源文件中读,向目标文件写。第11章 文件类型 程序如下:/*程序11-7,文件复制程序*/main(int argc,char *argv)int i;FILE *fps,*fp
32、t;if(argc!=3)puts(命令行参数格式是:执行文件名 源文件名 目标文件名);exit(0);if(fps=fopen(argv1,rb)=NULL)printf(源文件不能打开!);exit(0);第11章 文件类型 if(fpt=fopen(argv2,wb)=NULL)printf(目标文件不能建立!);exit(0);while(!feof(fps)fread(&i,2,1,fps);fwrite(&i,2,1,fpt);fclsoe(fps);fclose(fpt);第11章 文件类型 例11-8 将例11-5建立的磁盘文件STUDENT.DAT首先在屏幕上输出文件内容,
33、然后使指针移到开头,实现文件的复制。本题对文件的操作有显示输出和复制两种,但不是同时进行,故会涉及到指针移动,可用rewind()函数将源文件指针移回文件开头。第11章 文件类型 程序如下:/*程序11-8,文件的输出复制操作*/#define SIZE 200struct student int num;char *name;int age;float score;char *addr;stud;main()FILE *fp1,*fp2;char *tname;第11章 文件类型 int i=0;if(fp1=fopen(STUDENT.DAT,rb)=NULL)printf(不能打开文件!
34、);exit(0);while(!feof(fp1)/*屏幕输出*/fread(&stud,sizeof(struct student),1,fp1);printf(%6d%16s%8d%8.1f%28sn,stud.mum,stud.name,stud.age,stud.score,stud.addr);puts(请输入目标文件名);gets(tname);rewind(fp1);第11章 文件类型 if(fp2=fopen(tname,wb)=NULL)printf(不能建立文件!);exit(0);while(!feof(fp1)/*复制文件*/fread(&stud,sizeof(st
35、ruct student),1,fp1);fwrite(&stud,sizeof(struct student),1,fp2);fclose(fp1);fclose(fp2);第11章 文件类型 例11-9 某书店库存数据保存在库存文件BK中,每天的销售数据保存在销售文件BX中。编写程序,根据当天的销售数据调整库存文件。算法提示:(1)用一临时文件BT先保存调整后的库存。(2)从库存文件BK中读出库存数据减去从销售文件BX中读出的对应销售数据进行库存调整,写入临时库存文件BT。(3)操作完毕,将临时库存文件BT改名为原库存文件BK。第11章 文件类型 程序如下:/*程序11-9,文件合并操作*
36、/struct book char *name;int num;main()struct book b;int x;FILE *fk,*fx,*ft;if(fk=fopen(BK,rb)=NULL)printf(不能打开库存文件!);exit(0);第11章 文件类型 if(fx=fopen(BX,rb)=NULL)printf(不能打开销售文件!);exit(0);if(ft=fopen(BT,wb)=NULL)printf(不能打开临时库存文件!);exit(0);while(!feof(fk)/*进行调整*/fread(&b,sizeof(struct book),1,fk);fread
37、(&x,2,1,fx);第11章 文件类型 b.num=x;fwrite(&b,sizeof(struct book),1,ft);fcloseall();/关闭所有文件*/system(delete BK);/*删除原库存文件*/system(rename BT BK);/*将临时库存文件改名为原库存文件名*/第11章 文件类型 习习 题题 十十 一一 1文件类型与结构体类型有何关系?在程序中如何对文件进行操作?2简述文件建立、读取的一般过程。3从键盘输入一个字符串,将其中的字母存入一个磁盘文件中,非字母存入另一个磁盘文件中。4将1100之间的偶数与奇数分别用文件保存。5编写程序,求出100
38、0以内的素数,并用一文件保存。6从上题的文件中读取数据,将1000以内的素数打印输出。7编写程序,将一字符文件的内容反序保存至另一文件中。第11章 文件类型 8有若干个学生,每个学生包含学号、姓名、八门课成绩等信息,计算出每个学生的平均成绩,并将原始数据及平均成绩存入一个磁盘文件。9读取上题文件中的数据,将平均成绩不及格的学生数据与平均成绩大于85分的学生的数据分别用另外的文件保存。10某单位职工工资数据保存在文件gz.dat中,每个职工的数据包括姓名、职务工资、岗位津贴、扣款。编写程序,读取文件gz.dat中数据至一链表。11将第3题中的两个文件合并成一个文件,第二个文件的内容追加在第一个文件内容的后面。第11章 文件类型 12将两个排好序的整数文件合并成一个新文件,要求依然保持数据的顺序。13编写通讯录管理程序,通讯录数据用磁盘文件保存,一方面可追加数据和修改数据,另一方面可根据姓名查找数据。14编写类似DOS的TYPE命令的程序,输出命令行中参数所指定文件的内容。15编写程序,对n个文件的内容可选择依次显示或依次打印。16将例11-5改用链表完成处理。17对第9章习题18引入文件处理,重新编写程序。18对第10章习题22引入文件处理,重新编写程序。