《C语言程序设计与数据结构》课件第10章文件读写_第1页
《C语言程序设计与数据结构》课件第10章文件读写_第2页
《C语言程序设计与数据结构》课件第10章文件读写_第3页
《C语言程序设计与数据结构》课件第10章文件读写_第4页
《C语言程序设计与数据结构》课件第10章文件读写_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第10章文件读写教学提示:存储在变量和数组〔即内存〕中的数据是临时的,这些数据在程序运行结束后会消失,而文件可以用来永久地保存大量的数据。如果有些数据需要反复使用或永久保存,应该考虑使用文件来完成。教学要求:本章要掌握文件在读写之前必须翻开,读写结束必须关闭。文件可按只读、只写、读写、追加四种操作方式翻开,同时还必须指定文件的类型是二进制文件还是文本文件。文件可按字节,字符串,数据块为单位读写,文件也可按指定的格式进行读写。文件内部的位置指针可指示当前的读写位置,移动该指针可以对文件实现随机读写。10.1 文件概述与文件指针所谓“文件〞是指一组相关数据的有序集合。我们在前几章中已屡次接触使用过文件,例如源程序文件、目标文件、可执行文件、库文件(头文件)等。10.1.1文件分类文件通常是驻留在外部介质(如磁盘等)上的,在使用时才调入内存中来。C语言把文件看作是由一个个字符〔字节〕的数据顺序组成的。它把数据看作是连续的字符〔字节〕流,这样它对文件的存取实际上是以字符〔字节〕为单位的。输入输出的数据流的开始和结束只受程序的控制而不受特定符号〔比方回车换行符〕的控制。也就是说,C语言在输出数据到文件中时,并不会自动增加回车换行符以示结束,在输入时也不会以读入回车换行符作为数据的间隔。10.1.1文件分类从用户的角度看,文件可分为普通文件和设备文件两种。根据文件的存储形式,可分为ASCII码文件和二进制文件两种:(1)ASCII文件也称为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的ASCII码。例如一个整型数据1234在文本文件中占4个字节。我们用Windows自带的记事本软件翻开该类型文件能读懂文件中的内容。(2)二进制文件是按二进制的编码方式来存放文件的。例如一个整型数据230在二进制文件中占2个字节。10.1.2文件类型指针在C语言中要使用文件,必须用一个指针变量指向一个文件,这个指针称为文件指针。通过文件指针就可对它所指的文件进行各种操作。定义文件指针的一般形式为:FILE*指针变量标识符;其中FILE必须为大写,它是在头文件stdio.h中定义的一个结构体,该结构体中含有文件名、文件状态和文件当前位置等信息,我们编程时不必关心FILE结构的细节。例如:FILE*fp;表示定义了一个名为fp的文件指针。如果变量fp已被正确赋值,那么可以根据结构变量fp所提供的信息找到一个文件并实施对该文件的操作。习惯上把fp称为指向一个文件的指针。10.2 文件的翻开与关闭使用文件必须遵循“先翻开,再对文件进行读写操作,最后关闭文件〞的原那么。在C语言中,对文件的这些操作都可以由库函数来完成,对用到的库函数的声明包含在文件stdio.h中,因此在编程中要操作文件时,要使用头文件包含命令#include“stdio.h〞。10.2.1 文件的翻开所谓翻开文件,实际上是获得文件的各种有关信息,并使文件指针指向该文件,以便进行下一步操作。C语言提供了函数fopen来翻开文件。其使用格式为:文件指针名=fopen(文件名,使用文件方式);其中,“文件指针名〞必须是已被说明为FILE类型的指针变量;“文件名〞是将被翻开的文件的文件名,通常是字符串常量或字符串数组〔注意路径的分隔符应使用“\\〞〕;“使用文件方式〞是指文件的类型和操作要求,是一个由一对双引号括起来的字符串,共有12种,具体的符号表示和含义见表10-1。文件使用方式含义“rt”打开一个已经存在的文本文件,只能读取数据“wt”打开一个文本文件,只能写入数据。若文件不存在,则自动建立一个新文件接受写入的数据;若文件存在,则删除文件中原有内容,并接受写入的数据(覆盖)“a”打开一个已经存在的文本文件,只能写入数据并且追加在文件的尾部“r+”打开一个已经存在的文本文件,可以读取数据,也可以写入数据“w+”打开一个文本文件,可以读取数据,也可以写入数据。若文件不存在,则自动建立一个新文件接受写入的数据;若文件存在,则删除文件中原有内容,并接受写入的数据(覆盖)“a+”打开一个已经存在的文本文件,可以读取数据,也可以写入数据(追加在文件的尾部)“rb”打开一个已经存在的二进制文件,只能读取数据“wb”打开一个二进制文件,只能写入数据。若文件不存在,则自动建立一个新文件接受写入的数据;若文件存在,则删除文件中原有内容并接受写入的数据(覆盖)“ab”打开一个已经存在的二进制文件,只能写入数据(追加在文件的尾部)“rb+”打开一个已经存在的二进制文件,可以读取数据,也可以写入数据“wb+”打开一个二进制文件,可以读取数据,也可以写入数据。若文件不存在,则自动建立一个新文件接受写入的数据;若文件存在,则删除文件中原有内容,并接受写入的数据(覆盖)“ab+”打开一个已经存在的二进制文件,可以读取数据,也可以写入数据(追加在文件的尾部)fopen翻开文件例如:FILE*fpTa;fpTa=fopen("c:\\cprogram\\abc","rb");/*反斜线“\\〞中的第一个表示转义字符*/其意义是翻开C驱动器磁盘的cprogram子目录下的文件abc,这是一个二进制文件,只允许按二进制方式进行读操作。又如:FILE*fp;fp=fopen("mytest1.txt","r");其意义是在当前目录下翻开文件mytest1.txt,只允许进行“读〞操作,并使fp指向该文件。10.2.2 文件关闭函数在使用完一个文件以后,应该将该文件关闭,以防止它再被调用或丧失数据。“关闭〞就是使文件指针变量不再指向该文件,也就是文件指针变量与该文件“断开〞,此后不能通过该指针对原来与其相联系的文件进行读、写操作〔除非再次翻开该文件,使文件指针变量重新指向该文件〕。fclose()函数用来关闭一个已经由fopen()函数翻开的文件,正常完成关闭文件操作时,fclose函数返回值为0,有错误发生那么返回非零值。其调用的一般形式为:fclose(文件指针);例如:fclose(fp);10.3 文件位置指针的有关函数在文件内部有一个位置指针,用来指向文件的当前读写字节。在文件翻开时,该位置指针总是指向文件的第一个字节。使用下面章节介绍的fgetc等函数对文件进行读写后,该位置指针将自动向后移动。但文件指针和文件内部的位置指针不是一回事。文件指针是指向整个文件的,须在程序中定义说明,只要不重新赋值,文件指针的值是不变的。文件内部的位置指针用以指示文件内部的当前读写位置,每读写一次,该指针均自动向后移动,它不需在程序中定义说明,而是由系统自动设置的。顺序读写和随机读写文件的读写方式分为顺序读写和随机读写。(1)顺序读写即读写文件只能从头开始,顺序读写各个数据。但在实际问题中常要求只读写文件中某一指定的局部,为了解决这个问题可移动文件内部的位置指针到需要读写的位置,再进行读写,这种读写称为随机读写。(2)随机读写可以通过利用系统函数去主动移动文件内部的位置指针来实现。这样的函数主要有两个,即rewind函数和fseek函数。实现随机读写的关键是要按要求移动位置指针,这称为文件的定位。在移动位置指针之后,即可用后面介绍的任一种读写函数进行读写。由于一般是读写一个数据据块,因此常用fread和fwrite函数。rewind函数rewind函数的功能是把文件内部的位置指针移到文件首。其调用形式为:rewind(文件指针);“文件指针〞指向被移动的文件。fseek函数fseek函数用来移动文件内部位置指针,其调用形式为:fseek(文件指针,位移量,起始点);其中:“文件指针〞指向被移动的文件。“位移量〞表示移动的字节数,要求位移量是long型数据,以便在文件长度大于64KB时不会出错。当用常量表示位移量时,要求加后缀“L〞。“起始点〞表示从何处开始计算位移量,规定的起始点有三种:文件首,当前位置和文件尾。起始点表示符号数字表示文件首SEEK_SET0当前位置SEEK_CUR1文件末尾SEEK_END2例如:fseek(fp,100L,0);/*将文件位置指针移到离文件头100个字节处*/fseek(fp,20L,1);/*将文件位置指针从当前位置后移20个字节的位置*/fseek(fp,-10L,SEEK_END);/*将文件位置指针从文件末尾前移10个字节的位置*/注意:fseek函数一般用于二进制文件。在文本文件中由于要进行转换,往往计算的位置会出现错误。

ftell函数:用来得到流式文件中的当前位置,用相对于文件开头的位移量来表示。如返回-1L那么表示出错。例如:longa;a=ftell(fp);

文件结束检测函数feof函数feof()判断文件是否处于文件结束位置,如文件结束,那么返回值为1,否那么为0。其调用格式为:feof(文件指针);说明:文件结束标志EOF(每个文件末有一结束标志EOF,值为-1)只适用于判断文本文件是否结束。而函数feof()那么对文本文件和二进制文件都适用。10.4 读写文件

10.4.1 字符读写函数fgetc和fputc是以字符(字节)为单位的读写函数。每次可从文件读出或向文件写入一个字符。字符输入/出函数所处理的文件可以是文本文件,也可以是二进制文件。

10.4.2 字符串读写函数fgets和fputs处理的文件一般是文本文件,读写的数据以字符串为单位。10.4.3 数据块读写函数fread和fwtrite用于整块数据的读写函数。可用来读写一组数据,如一个数组、一个结构变量的值等。10.4.4 格式化读写函数fscanf和fprintf与前面使用的scanf和printf函数的功能相似,都是格式化读写函数。两者的区别在于fscanf函数和fprintf函数的读写对象不是键盘和显示器,而是磁盘文件。

读字符函数fgetcfgetc函数的功能是从指定的文件中读取一个字符,函数调用的一般形式为:字符变量=fgetc(文件指针);例如:ch=fgetc(fp);其意义是从翻开的文件fp中读取一个字符并送入字符变量ch中。对于fgetc函数的使用有以下几点说明:(1)在fgetc函数调用中,读取的文件必须是以读或读写方式翻开的。(2)读取字符的结果也可以不向字符变量赋值,例如fgetc(fp);但是读出的字符不能保存。(3)文件内部的位置指针在文件翻开时总是指向文件的第一个字节。使用fgetc函数后,该位置指针将向后移动一个字节。因此可连续屡次使用fgetc函数来读取多个字符。【例10.1】将C盘根目录下的文本文件test1.txt的内容在屏幕上输出。#include<stdio.h>main(){FILE*fp;/*定义了文件指针fp*/charch;if((fp=fopen("c:\\test1.txt","r"))==NULL)/*以读文本文件方式翻开并使fp指向该文件*/{printf("\nCannotopenfile,strikeanykeytoexit!");getchar();exit(1);}ch=fgetc(fp);/*先读出一个字符,然后进入循环*/while(ch!=EOF)/*判断文件是否结束*/{putchar(ch);/*把该字符显示在屏幕上*/ch=fgetc(fp);/*再读入下一字符*/}fclose(fp);printf(“\n〞);}本例程序的功能是从文件中逐个读取字符,并在屏幕上显示。如翻开文件出错,给出提示并退出程序。只要读出的字符不是文件结束标志EOF,就把该字符显示在屏幕上,再读入下一字符。每读一次,文件内部的位置指针向后移动一个字符,文件结束时,该指针指向EOF。执行本程序将显示文件c:\test1.txt的所有内容。写字符函数fputc()fputc函数的功能是把一个字符写入指定的文件中,如写入成功那么返回写入的字符,否那么返回一个EOF,可用此来判断写入是否成功。函数调用形式为:fputc(字符量,文件指针);/*字符量是待写入的字符常量或变量*/例如:fputc('x',fp);其意义是把字符‘x’写入fp所指向的文件的位置指针的当前位置中。每写入一个字符,文件内部位置指针向后移动一个字节。

被写入的文件可以用写、读写、追加方式翻开。【例10.2】将从键盘上输入的一些字符〔以“*〞作为结束〕写入c盘根目录下名为test2.txt的文本文件中。#include"stdio.h"main(){FILE*p; charch; if((p=fopen("c:\\test2.txt","w"))==NULL) {printf("Filecannotopen!\n"); exit(0); } printf("Pleaseinput,endinputwith*character:"); while((ch=getchar())!='*') fputc(ch,p); fclose(p); printf("Writeover!\n"); }程序运行结束后,可以在c盘根目录下翻开test2.txt查看其内容。思考一下,如果在写入完毕后想马上把刚刚输入的内容打印在屏幕上该如何实现?字符串输入/出函数字符串输入/出函数所处理的文件一般是文本文件,读写的数据以字符串为单位。1. 读字符串函数fgets功能是从指定的文件中读一个字符串到字符数组中.函数调用的形式为:fgets(字符数组名,n,文件指针);其中n是一个正整数。该函数表示从文件中读出n-1个字符〔如在读满n-1个字符之前就遇到了换行符或EOF,那么读出提前结束〕,并在读取的最后一个字符后加上串结束标志'\0'。fgets函数的返回值是字符数组的首地址。读取字符串后文件位置指针也自动后移假设干个位置。例如:fgets(str,n,fp);意义是从fp所指的文件中读出n-1个字符送入字符数组str中。【例10.3】从test2.txt文件中读入8个字符组成一个字符串。#include<stdio.h>main(){FILE*fp;chararr[20];if((fp=fopen("c:\\test2.txt","r"))==NULL){printf("\nCannotopenfile,strikeanykeyexit!");getchar();exit(1);}fgets(arr,9,fp);printf("\n%s\n",arr);fclose(fp);}本例定义了一个字符数组str共20个字节,在以读文本文件方式翻开文件string后,从中读出8个字符送入str数组,在第9个数组元素str[8]内加上'\0',然后在屏幕上显示输出str数组存放的字符串。输出的八个字符正是例10.2的前八个字符。2. 写字符串函数fputsfputs函数的功能是向指定的文件写入一个字符串〔不写入字符串结束标记'\0'〕,当成功写入一个字符串后,文件的位置指针会自动后移,函数返回值为0;否那么,返回EOF〔符号常量,其值为-1〕。其调用形式为:fputs(字符串,文件指针);其中字符串可以是字符串常量,也可以是字符数组名或指针变量。例如:fputs(“a1b2〞,fp)是把字符串“a1b2〞写入fp所指的文件之中。【例10.4】在文件test2.txt中追加一个不超过20个字符的字符串。#include<stdio.h>main(){FILE*fp;charch,st[21];intcount;if((fp=fopen("c:\\test2.txt","a+"))==NULL){printf("Cannotopenfilestrikeanykeyexit!");getchar();exit(1);}printf("inputastring:\n");gets(st);/*输入不超过20个字符的字符串暂放入数组st中*/fputs(st,fp);rewind(fp);/*文件内部位置指针移到文件的开始位置*/printf(“\nAllofthisfileis:\n〞);ch=fgetc(fp);while(ch!=EOF){putchar(ch);ch=fgetc(fp);}printf("\n");fclose(fp);}本例要求在test2.txt文件末添加一个字符串,因此,在程序第7行以追加读写文本文件的方式翻开文件test2.txt。然后输入字符串暂放入数组st中,并用fputs函数把该串写入文件test2.txt。后在程序中用rewind函数把文件内部位置指针移到文件首,再进入循环逐个显示当前文件中的全部内容。要注意用scanf(“%s〞,st)和gets(st)输入字符串时的不同。思考:如果不用EOF,而是用feof()来判断文件结束,上述阴影局部程序该如何改写?数据块读写函数fread和fwtriteC语言还提供了用于整块数据的读写函数。可用来读写一组数据,如一个数组、一个结构变量的值等。读数据块函数调用的一般形式为:fread(buffer,size,count,fp);写数据块函数调用的一般形式为:fwrite(buffer,size,count,fp);其中:

size表示每个数据块的字节数。

count表示要读写的数据块块数。fp表示文件指针。buffer是一个指针。

fread(buffer,size,count,fp)的功能是从fp所指向文件的位置指针的当前位置读取count块数据〔每个数据所占的字节数为size〕,共组成count块长度为size的数据存入butter所指定的内存空间中,当正确的读取了count块数据后,文件内部指针会自动后移count*size个字节的位置,假设数据存入正确,那么返回count值,否那么返回NULL〔符号常量,其值为0〕。例如:fread(fa,4,5,fp);其意义是从fp所指的文件中,每次读4个字节(一个实数)送入实型数组fa中,连续读5次,即读5个实数到fa中。fwrite(buffer,size,count,fp)表示将从buffer起始地址的count块数据〔每块数据的字节数为size〕写入到fp所指向的文件中,当正确的写入count块数据后,文件位置指针会自动后移count*size个字节的位置。假设数据写入正确,那么返回count值;否那么返回NULL〔符号常量,其值为0〕。【例10.5】从键盘上输入10个整数,并把这些整数写入c:盘根目录下名为test3.dat的二进制文件中。#include"stdio.h"main(){FILE*fp; intdata[10],i; if((fp=fopen("c:\\test3.dat","wb"))==NULL) {printf("Filecannotopen!\n"); exit(0); } printf(“Inputtenintegers:〞); for(i=0;i<10;i++) scanf("%d",&data[i]); fwrite(data,sizeof(int),10,fp); fclose(fp); printf(“Writeover!\n〞);}【例10.6】

从c:盘根目录下名为test3.dat的二进制文件中读取10个整数,要求先读取第6~10个整数,再读取第1~5个整数。并把它们输出到屏幕上显示。#include"stdio.h"main(){FILE*fp; intdata[10],i; if((fp=fopen("c:\\test3.dat","rb"))==NULL) {printf("Filecannotopen!\n"); exit(0); }fseek(fp,5L*sizeof(int),0);/*先把文件位置指针后移*/

fread(data,sizeof(int),5,fp);/*先读取第6~10个整数放入data[0]~data[4]*/ rewind(fp);/*把文件位置指针移到文件开始*/

fread(data+5,sizeof(int),5,fp);/*再读取第1~5个整数放入data[5]~data[9]*/ fclose(fp); for(i=0;i<10;i++) printf("%5d",data[i]);}

【例10.7】从键盘输入三个学生数据,写入一个文件中,再读出这两个学生的数据显示在屏幕上。#include<stdio.h>structstu{charname[20];intnum;intage;charaddr[30];}boya[3],boyb[3],*pp,*qq;main(){FILE*fp;inti;pp=boya;qq=boyb;if((fp=fopen("c:\\studata","wb+"))==NULL){printf("Cannotopenfilestrikeanykeyexit!");getchar();exit(1);}

for(i=0;i<3;i++,pp++){ printf("inputnamenumageaddr:\n"); scanf("%s%d%d%s",pp->name,&pp->num,&pp->age,pp->addr);}pp=boya;fwrite(pp,sizeof(structstu),3,fp);rewind(fp);fread(qq,sizeof(structstu),3,fp);fclose(fp);printf("\n\nname\tnumberageaddr\n");for(i=0;i<3;i++,qq++) printf("%s\t%5d%7d%s\n",qq->name,qq->num,qq->age,qq->addr);}

本例程序定义了一个结构stu,说明了两个结构数组boya和boyb以及两个结构指针变量pp和qq。pp指向boya,qq指向boyb。程序首先以读写方式翻开二进制文件“studata〞,输入三个学生数据之后,写入该文件中。然后把文件内部位置指针移到文件首,读出三块学生数据后,在屏幕上显示。格式化读写函数fscanf和fprintffscanf函数,fprintf函数与前面使用的scanf和printf函数的功能相似,都是格式化读写函数。两者的区别在于fscanf函数和fprintf函数的读写对象不是键盘和显示器,而是磁盘文件。这两个函数的调用格式为:fscanf(文件指针,格式字符串,输入表列);fprintf(文件指针,格式字符串,输出表列);例如:

fscanf(fp,"%d%s",&i,s);fprintf(fp,"%d%c",j,ch);用fscanf和fprintf函数也可以完成例10.7的问题。修改后的程序如例10.8所示。

【例10.8】用fscanf和fprintf函数解决例10.7的问题。#include<stdio.h>structstu{charname[20];intnum;intage;charaddr[30];}boya[3],boyb[3],*pp,*qq;main(){FILE*fp;inti;pp=boya;qq=boyb;if((fp=fopen("c:\\studata","wb+"))==NULL){printf("Can’topenfilestrikeanykeyexit!");getch();exit(1);}printf("\ninputdata\n");for(i=0;i<3;i++,pp++)scanf("%s%d%d%s",pp->name,&pp->num,&pp->age,pp->addr);pp=boya;for(i=0;i<3;i++,pp++)fprintf(fp,"%s%d%d%s\n",pp->name,pp->num,pp->age,pp->addr);rewind(fp);for(i=0;i<3;i++,qq++)fscanf(fp,"%s%d%d%s\n",qq->name,&qq->num,&qq->age,qq->addr);printf("\n\nname\tnumberageaddr\n");qq=boyb;for(i=0;i<3;i++,qq++)printf("%s\t%5d%7d%s\n",qq->name,qq->num,qq->age,qq->addr);fclose(fp);}

本程序中fscanf和fprintf函数每次只能读写一个结构体数组元素,因此采用了循环语句来读写全部数组元素。

还要注意指针变量pp,qq。由于循环改变了它们的值,因此在程序中分别对它们重新赋予了数组的首地址。

【例10.9】把命令行参数中的前一个文件名标识的文件,复制到后一个文件名标识的文件中,如命令行中只有一个文件名那么把该文件写到标准输出文件(显示器)中。#include<stdio.h>main(intargc,char*argv[]){FILE*fp1,*fp2;charch;if(argc==1)/*如命令行参数中没有给出文件名,那么给出提示信息*/{printf("Havenotenterfilename,strikeanykeyexit");getchar();exit(0);}if((fp1=fopen(argv[1],"rt"))==NULL){printf("Cannotopen%s\n",argv[1]);getchar();exit(1);}…….if(argc==2)/*如果只给出一个文件名,那么使fp2指向标准输出文件(即显示器)*/fp2=stdout;elseif((fp2=fopen(argv[2],"wt+"))==NULL){printf("Cannotopen%s\n",argv[1]);getchar();exit(1);}while((ch=fgetc(fp1))!=EOF)/*用循环语句逐个读出文件1中的字符再送到文件2中*/fputc(ch,fp2);fclose(fp1);fclose(fp2);}

本程序为带参数的main函数。程序中定义了两个文件指针fp1和fp2,分别指向命令行参数中给出的文件。如命令行参数中没有给出文件名,那么给出提示信息。如果只给出一个文件名,那么使fp2指向标准输出文件(即显示器)。然后用循环语句逐个读出文件1中的字符再送到文件2中。假设工

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论