实验11文件 【实验目的】 1.熟悉掌握文件的基本概念: 2.熟悉掌握文件的打开和关闭操作方法: 3.熟悉掌握文件的读写方法。 【相关知识点】 1.文件类型指针的定义 文件类型指针的定义一般格式为: FLE*文件指针名: FLE是一个己经由系统定义好的类型结构体,用来存放文件的有关信息。 示例: FILE *fp:; fp是一个指向FLE类型结构体的指针变量,让指向某一个文件结构体变量,就可以 通过间接访问到该文件。 2.文件的打开和关闭: 文件使用的正确顺序为: 打开文件→读写文件·关闭文件 对文件的基本操作可以使用C语言标准输入输出函数库中的相关函数来完成。 (1)文件的打开(fopen函数) 文件打开函数fopen()的一般调用形式为: fopen("文件名","文件打开方式")方 其中,函数的两个参数“文件名”、“文件打开方式”都是字符串。“文件名”指明打开的 是哪个文件,“文件打开方式”指明文件打开后可以进行的操作,具体的打开方式如下: "":打开文本文件进行只读操作。若文件不存在,则出错。 "w":打开文本文件进行只写操作。若文件已存在,则覆盖:文件不存在,则新建。 -214-
实验 11 文件 【实验目的】 1. 熟悉掌握文件的基本概念; 2. 熟悉掌握文件的打开和关闭操作方法; 3. 熟悉掌握文件的读写方法。 【相关知识点】 1. 文件类型指针的定义 文件类型指针的定义一般格式为: FILE *文件指针名; FILE 是一个已经由系统定义好的类型结构体,用来存放文件的有关信息。 示例: FILE *fp; fp 是一个指向 FILE 类型结构体的指针变量,让 fp 指向某一个文件结构体变量,就可以 通过 fp 间接访问到该文件。 2. 文件的打开和关闭: 文件使用的正确顺序为: 打开文件 → 读写文件 → 关闭文件 对文件的基本操作可以使用 C 语言标准输入输出函数库中的相关函数来完成。 (1)文件的打开(fopen 函数) 文件打开函数 fopen( )的一般调用形式为: fopen( "文件名", "文件打开方式" ); 其中,函数的两个参数“文件名”、“文件打开方式”都是字符串。“文件名”指明打开的 是哪个文件,“文件打开方式”指明文件打开后可以进行的操作,具体的打开方式如下: "r":打开文本文件进行只读操作。若文件不存在,则出错。 "w":打开文本文件进行只写操作。若文件已存在,则覆盖;文件不存在,则新建。 - 214 -
"a":打开文本文件进行追加写入操作。若文件不存在,则出错。 "r+":打开文本文件进行读写操作。若文件不存在,则出错。 "w+”:打开文本文件进行读写操作。若文件已存在,则覆盖:文件不存在,则新建。 "+":打开文本文件进行读写操作。若文件己存在,则追加写入:文件不存在,则出错。 "b":打开文本/文件进行只读操作。若文件不存在,则出错。 "b”:打开二进制文件进行只写操作。若文件己存在,则覆盖:文件不存在,则新建。 "b":打开二进制文件进行追加写入操作。若文件不存在,则出错。 "b+":打开二进制文件进行读写操作。若文件不存在,则出错。 "b+":打开二进制文件进行读写操作。若文件已存在,则覆盖:文件不存在,则新建。 "b+":打开二进制文件进行读写操作。若文件已存在,则追加写入:文件不存在,则出 错。 示例: FILE *fp; if(fp=fopen("abc.txt","r"))==NULL) printf("打开文件失败!n");方 exit(0); } 该示例表示以只读的方式打开一个已经存在的文件abc.txt。这是打开文件常用的办法:对 文件是否打开成功进行检测,如果文件打开失败,即fopent()函数的值为NULL,除了向显示 屏输出错误信息外,还终止程序的执行。 (2)文件的关闭(fclose函数) 文件使用完成后,为防止被再次误操作或者丢失数据,应通过调用fclose()函数关闭该文 件。 文件关闭函数felose()的一般调用形式为: fclose(文件指针名)方 示例: FILE *fp; if(fp=fopen("file.txt","w"))==NULL) -215-
"a":打开文本文件进行追加写入操作。若文件不存在,则出错。 "r+":打开文本文件进行读写操作。若文件不存在,则出错。 "w+":打开文本文件进行读写操作。若文件已存在,则覆盖;文件不存在,则新建。 "a+":打开文本文件进行读写操作。若文件已存在,则追加写入;文件不存在,则出错。 "rb":打开文本/文件进行只读操作。若文件不存在,则出错。 "wb":打开二进制文件进行只写操作。若文件已存在,则覆盖;文件不存在,则新建。 "ab":打开二进制文件进行追加写入操作。若文件不存在,则出错。 "rb+":打开二进制文件进行读写操作。若文件不存在,则出错。 "wb+":打开二进制文件进行读写操作。若文件已存在,则覆盖;文件不存在,则新建。 "ab+":打开二进制文件进行读写操作。若文件已存在,则追加写入;文件不存在,则出 错。 示例: FILE *fp; if(fp=fopen("abc.txt","r"))==NULL) { printf("打开文件失败!\n"); exit(0); } 该示例表示以只读的方式打开一个已经存在的文件 abc.txt。这是打开文件常用的办法:对 文件是否打开成功进行检测,如果文件打开失败,即 fopen( )函数的值为 NULL,除了向显示 屏输出错误信息外,还终止程序的执行。 (2)文件的关闭(fclose 函数) 文件使用完成后,为防止被再次误操作或者丢失数据,应通过调用 fclose( )函数关闭该文 件。 文件关闭函数 fclose( )的一般调用形式为: fclose( 文件指针名 ); 示例: FILE *fp; if(fp=fopen("file.txt","w"))==NULL) - 215 -
printf("打开文件失败!n"), exit(O)房 } fclose(fp); 该示例中fclose(fp);少语句表示关闭文件指针fp所指向的文件。 3.文件的读写函数: 字符读写函数一fgetc()和fputc() 字符串读写函数一—一fputs(()和fgets() 格式化读写函数一fscanf()和fprintf() 二进制读写函数一fread()和fwrite() 4. 文件的其他函数: 判断文件结束函数一feof) 重置文件指针回文件头函数一rewind() 随机定位文件指针函数一fseek() 【实验任务】 一、程序改错 该部分实验主要训练学生读简单程序的能力,并在理解程序的基础上,改正程序中出现 的问题,这些问题都是初学者经常容易犯的错误,针对文件这一章,主要有如下问题: 1)不能正确使用fopen()、fclose()函数,比如文件打开方式出错等: 2)文件类型指针定义或者赋值错误: 3)对一些文件操作库函数使用不正确。 针对上面的问题,查找下面程序中存在的问题,并改正调试。 1.打开c:\c-programming\11 pg11101.cpp,该程序将建立一个文本文件al.txt,并向该文 件写入一串以回车符结束的字符,最后关闭文件。该程序有两个小问题,程序不能正确运行。 请修改,使程序能正确运行。修改后的程序以pgI1101ok.cpp保存。该源程序内容如下: -216-
{ printf("打开文件失败!\n"); exit(0); } fclose(fp); 该示例中 fclose(fp);语句表示关闭文件指针 fp 所指向的文件。 3. 文件的读写函数: 字符读写函数——fgetc( ) 和 fputc( ) 字符串读写函数——fputs( ) 和 fgets( ) 格式化读写函数——fscanf( ) 和 fprintf( ) 二进制读写函数——fread( ) 和 fwrite( ) 4. 文件的其他函数: 判断文件结束函数——feof( ) 重置文件指针回文件头函数——rewind( ) 随机定位文件指针函数——fseek( ) 【实验任务】 一、程序改错 该部分实验主要训练学生读简单程序的能力,并在理解程序的基础上,改正程序中出现 的问题,这些问题都是初学者经常容易犯的错误,针对文件这一章,主要有如下问题: 1) 不能正确使用 fopen()、fclose()函数,比如文件打开方式出错等; 2) 文件类型指针定义或者赋值错误; 3) 对一些文件操作库函数使用不正确。 针对上面的问题,查找下面程序中存在的问题,并改正调试。 1.打开 c:\c-programming\11\pg11101.cpp,该程序将建立一个文本文件 a1.txt,并向该文 件写入一串以回车符结束的字符,最后关闭文件。该程序有两个小问题,程序不能正确运行。 请修改,使程序能正确运行。修改后的程序以 pg11101_ok.cpp 保存。该源程序内容如下: - 216 -
#include #include void main(void) int i; char c; FILE *fp; if((fp=fopen("al.txt",w))==NULL) { printf"文件打开错误!n")方 exit(O)方 } printf("请输入写入文件的字符串:"), for(i=0;(c=getchar()!=\n';i++) fputc(c,fp月 fclose(*fp); } 了提示:如何发现问题? 编译该程序,系统报告两条错误信息。第一条出现在程序第8行,即语句 if((fp=fopen("al.txt",w))=NULL) 错误信息如下: error C2065:'w:undeclared identifier(没定义的标识符) 也就是w被认为是一个变量,由于前面没有关于它的定义,系统认为该变量使用有错误。 但根据fopen()函数的使用要求,函数的2个参数都应该是字符串,故此处真正存在的问题是 需将w改成字符串类型。系统报告另外一个错误在程序第16行,即语句 fclose(*fp); 错误信息如下: error C2664:'fclose':cannot convert parameter 1 from 'struct_iobuf to'struct_iobuf * 将参数类型从结构体转换为结构体指针类型)。 -217-
#include #include void main(void) { int i; char c; FILE *fp; if((fp=fopen("a1.txt",w))==NULL) { printf("文件打开错误!\n"); exit(0); } printf("请输入写入文件的字符串:"); for(i=0;(c=getchar())!='\n';i++) fputc(c,fp); fclose(*fp); } 提示:如何发现问题? 编译该程序,系统报告两条错误信息。第一条出现在程序第 8 行,即语句 if((fp=fopen("a1.txt",w))==NULL) 错误信息如下: error C2065: 'w' : undeclared identifier(没定义的标识符) 也就是 w 被认为是一个变量,由于前面没有关于它的定义,系统认为该变量使用有错误。 但根据 fopen( )函数的使用要求,函数的 2 个参数都应该是字符串,故此处真正存在的问题是 需将 w 改成字符串类型。系统报告另外一个错误在程序第 16 行,即语句 fclose(*fp); 错误信息如下: error C2664: 'fclose' : cannot convert parameter 1 from 'struct _iobuf' to 'struct _iobuf *'(不能 将参数类型从结构体转换为结构体指针类型)。 - 217 -
原因在于fclose()函数要求参数为指向文件结构体的指针,根据变量定义,fp是文件类型 指针,但*p是结构体类型,所以导致参数类型出错。 改正程序后的运行结果示例如图11.1.1()所示,程序正确运行后生成的文件用记事本打开 后如图11.1.16b)所示。 e四"C:\c-programming\1 1\Debug\pg11101ok.exe-回☒ 请输入写入文件的字符串:he11o Press any key to continue 图11.1.1(a)pg11101_ok.cpp的运行结果 圆al.txt-记事本 口▣☒ 文件)编损⑧)格式Q)查看Y)帮助) hello Ln 1,Col 图11.1.1(b)pgl1101_ok.cpp运行生成的文件 2.打开c:\c-programming\11\pg111002.cpp,该程序能将两个已有的文本文件datal.txt、 data2.txt的内容在屏幕输出显示。该程序有一个小问题,请修改,使程序能正确运行。修改后 的程序以pgl1102_ok.cpp保存。该源程序内容如下: #include #include void main(void) FILE *fpl,fp2; if((fp1=fopen("datal.txt","r"))-=NULL) { printf"文件datal.tt打开错误!n")方 exit(O); } if((fp2=fopen("data2.txt","r"))-=NULL) printf"文件data2.tt打开错误!n"); exit(0); -218-
原因在于 fclose( )函数要求参数为指向文件结构体的指针,根据变量定义,fp 是文件类型 指针,但*fp 是结构体类型,所以导致参数类型出错。 改正程序后的运行结果示例如图 11.1.1(a)所示,程序正确运行后生成的文件用记事本打开 后如图 11.1.1(b)所示。 图 11.1.1(a) pg11101_ok.cpp 的运行结果 图 11.1.1(b) pg11101_ok.cpp 运行生成的文件 2.打开 c:\c-programming\11\pg11102.cpp,该程序能将两个已有的文本文件 data1.txt、 data2.txt 的内容在屏幕输出显示。该程序有一个小问题,请修改,使程序能正确运行。修改后 的程序以 pg11102_ok.cpp 保存。该源程序内容如下: #include #include void main(void) { FILE *fp1,fp2; if((fp1=fopen("data1.txt","r"))==NULL) { printf("文件 data1.txt 打开错误!\n"); exit(0); } if((fp2=fopen("data2.txt","r"))==NULL) { printf("文件 data2.txt 打开错误!\n"); exit(0); - 218 -
} printf("datal.txt文件的内容为:")方 while(feof(fp1)) putchar(fgetc(fpl)); printf"n")方 printf("data2.txt文件的内容为:"): while(feof(fp2)) putchar(fgetc(fp2)); printf("In"), fclose(fpl)方 fclose(fp2方 了提示:如何发现问题? 编译该程序,系统报告四条错误信息。第一条在程序的第11行,即语句 if((fp2=fopen("data2.txt","r"))==NULL) 错误信息如下: error C2679:binary=:no operator defined which takes a right-hand operand of type 'struct iobuf *'(or there is no acceptable conversion) 该出错信息指出语句中的赋值不正确,也就是为变量2赋值不正确。但语句 if((fpl=fopen("datal.txt","r"))==NULL) 的用法与该语句的用法一致,却没有出现报错信息,说明1和p2可能存在类型上的不 同,故重点检查fpl和p2的定义语句,即语句: FILE *fpl,fp2; 发现该语句的变量定义确实存在问题。修改此处的错误后,程序编译通过,但运行结果 不正确,文件中没有任何字符被读出显示。启用单步运行调试程序发现,程序中两条while循 环语句的循环体一次也没有被执行到,未从文件中读出任何字符,也就是说循环条件fopl)、 feof(fp:2)可能出现了错误。分析程序,在读文件时,当文件类型指针没指向文件尾,feof)函 数的值为0,此时循环条件不成立,因此循环体中的读写文件的语句不被执行,因此没有任何 字符输出。按照分析及程序的要求,修改循环条件使程序运行结果正确。 -219-
} printf("data1.txt 文件的内容为:"); while(feof(fp1)) putchar(fgetc(fp1)); printf("\n"); printf("data2.txt 文件的内容为:"); while(feof(fp2)) putchar(fgetc(fp2)); printf("\n"); fclose(fp1); fclose(fp2); } 提示:如何发现问题? 编译该程序,系统报告四条错误信息。第一条在程序的第 11 行,即语句 if((fp2=fopen("data2.txt","r"))==NULL) 错误信息如下: error C2679: binary '=' : no operator defined which takes a right-hand operand of type 'struct _iobuf *' (or there is no acceptable conversion) 该出错信息指出语句中的赋值不正确,也就是为变量 fp2 赋值不正确。但语句 if((fp1=fopen("data1.txt","r"))==NULL) 的用法与该语句的用法一致,却没有出现报错信息,说明 fp1 和 fp2 可能存在类型上的不 同,故重点检查 fp1 和 fp2 的定义语句,即语句: FILE *fp1,fp2; 发现该语句的变量定义确实存在问题。修改此处的错误后,程序编译通过,但运行结果 不正确,文件中没有任何字符被读出显示。启用单步运行调试程序发现,程序中两条 while 循 环语句的循环体一次也没有被执行到,未从文件中读出任何字符,也就是说循环条件 feof(fp1)、 feof(fp2)可能出现了错误。分析程序,在读文件时,当文件类型指针没指向文件尾,feof( )函 数的值为 0,此时循环条件不成立,因此循环体中的读写文件的语句不被执行,因此没有任何 字符输出。按照分析及程序的要求,修改循环条件使程序运行结果正确。 - 219 -
改正程序后的运行结果示例如图11.1.2所示。 "C:\c-programming\11\Debug\pg11102_ok.exe" data1.txt文件的内容为:123456 data2.txt文件的内容为:abcdefg Press any key to continue 图11.1.2pgI1102_ok.cpp的运行结果 二、程序扩展 l.打开c:c-programming\11\pg11201.cpp,该程序能够从一个已有的文本文件data3.tt读 出所有的字符显示输出。该源程序内容如下: #include #include void main(void) FILE *f3; char ch: if((f3=fopen("data3.txt","r"))==NULL) { printf("文件打开错误!n"); exit(O), } printf"data3.tt文件的内容为:"); while(!feof(f3)) ch=fgetc(f3)方 putchar(ch); } printf("In"); fclose(f3); -220-
改正程序后的运行结果示例如图 11.1.2 所示。 图 11.1.2 pg11102_ok.cpp 的运行结果 二、程序扩展 1.打开 c:\c-programming\11\pg11201.cpp,该程序能够从一个已有的文本文件 data3.txt 读 出所有的字符显示输出。该源程序内容如下: #include #include void main(void) { FILE *f3; char ch; if((f3=fopen("data3.txt","r"))==NULL) { printf("文件打开错误!\n"); exit(0); } printf("data3.txt 文件的内容为:"); while(!feof(f3)) { ch=fgetc(f3); putchar(ch); } printf("\n"); fclose(f3); } - 220 -
要求1:修改上面的程序,使程序增加以下功能:从键盘输入任意字符,统计出文件中该 字符出现的次数,并将次数追加写入到文件的末尾。修改结果源程序以pgl120la.cpp保存。 训练要点:使用函数fopen()打开文件,尤其是掌握函数参数“文件打开方式”的具体含 义,以及如何使用字符读写函数读写文件。 修改后程序的运行结果如图11.1.3所示。 "C:\c-programming\11\Debug\pg11201a.exe" 回 情输入需要统计个数的字符:” data3,txt文件的内容为:c-programming 共出现了2次r字符 Press any key to continue 图11.1.3pgl1201a.cpp的运行结果 2.打开c:lc-programming1Ipgl1202.cpp,该程序能够将文本文件data4.txt的内容复制到 一个新建文件a2.txt,并将a2.tt的内容在屏幕上显示输出。该源程序内容如下: #include void main(void) { char c; FILE *fp1,*fp2; if((fpl=fopen("data4.txt","r"))==NULL) { printf"文件打开错误!n")方 exit(O)方 } if((fp2=fopen("a2.txt","w"))-NULL) { printf("文件打开错误!n")方 exit(O)方 } while(!feof(fp1)) -221-
要求 1:修改上面的程序,使程序增加以下功能:从键盘输入任意字符,统计出文件中该 字符出现的次数,并将次数追加写入到文件的末尾。修改结果源程序以 pg11201a.cpp 保存。 训练要点:使用函数 fopen( )打开文件,尤其是掌握函数参数“文件打开方式”的具体含 义,以及如何使用字符读写函数读写文件。 修改后程序的运行结果如图 11.1.3 所示。 图 11.1.3 pg11201a.cpp 的运行结果 2.打开 c:\c-programming\11\pg11202.cpp,该程序能够将文本文件 data4.txt 的内容复制到 一个新建文件 a2.txt,并将 a2.txt 的内容在屏幕上显示输出。该源程序内容如下: #include #include void main(void) { char c; FILE *fp1,*fp2; if((fp1=fopen("data4.txt","r"))==NULL) { printf("文件打开错误!\n"); exit(0); } if((fp2=fopen("a2.txt","w"))==NULL) { printf("文件打开错误!\n"); exit(0); } while(!feof(fp1)) - 221 -
c=fgetc(fp1); fputc(c,fp2)方 } fclose(fpl)方 fclose(fp2方 if((fp2=fopen("a2.txt","r"))==NULL) { printf("文件打开错误!n")方 exit(O), } printf("a2.txt文件的内容为:"); while(!feof(fp2)) { c=fgetc(fp2); putchar(c方 } printf("n")方 fclose(fp2), 要求1:修改上面的程序,使程序能够将data4.txt的内容复制到a2.txt的同时实现大小写 字母互相转换,其余字符不变。修改结果源程序以pgl1202a.cpp保存。 训练要点:使用函数fopen()打开文件,尤其是掌握函数参数“文件打开方式”的具体含 义,以及如何使用字符读写函数读写文件。 修改后程序的运行结果如图11.1.4所示。 e"C:\c-programming\11\Debug\pg11202a.exe" a2.txt文件的内容为:He is Tom. Press any key to continue 4 图11.1.4pgl1202a.cpp的运行结果 -222-
{ c=fgetc(fp1); fputc(c,fp2); } fclose(fp1); fclose(fp2); if((fp2=fopen("a2.txt","r"))==NULL) { printf("文件打开错误!\n"); exit(0); } printf("a2.txt 文件的内容为:"); while(!feof(fp2)) { c=fgetc(fp2); putchar(c); } printf("\n"); fclose(fp2); } 要求 1:修改上面的程序,使程序能够将 data4.txt 的内容复制到 a2.txt 的同时实现大小写 字母互相转换,其余字符不变。修改结果源程序以 pg11202a.cpp 保存。 训练要点:使用函数 fopen( )打开文件,尤其是掌握函数参数“文件打开方式”的具体含 义,以及如何使用字符读写函数读写文件。 修改后程序的运行结果如图 11.1.4 所示。 图 11.1.4 pg11202a.cpp 的运行结果 - 222 -
要求2:在源程序pg11202.cpp中,为了读出a2.xt文件的内容,采用了先关闭再重新打 开该文件的方法。请修改程序,使得只用打开一次文件就完成写入和读出操作。修改结果源 程序以pgl1202b.cpp保存。 训练要点:使用文件定位函数,如rewind()、fseek()等重置文件位置指针。 修改后程序的运行结果如图11.1.5所示。 "C:\c-programming\11\Debug\pg11202b.exe" a2.txt文件的内容为:hE IS to州. Press any key to continue 图11.1.5pg11202b.cpp的运行结果 三、程序编写 1.编写程序,统计一个有多行内容的文本文件text1txt的行数。编写的源程序以 Pgl1301.cpp保存。 提示:文本文件textl.txt可以先采用记事本自行创建并输入自定内容后保存。 训练要点:文件的打开、关闭以及使用字符写入函数对文件进行写入操作。 程序运行结果参考示例如图11.1.6所示。 "C:\c-programming\11\Debug\pg11301.exe" 回☒ tet1.txt文件的内容如下: 低头思敌乡 该文件共有5行 Press any key to continue 图11.1.6pgl1301.cpp的运行结果 2.编写程序,将一个文本文件text2-1.txt中的所有空格去掉后,存放到另外一个文件 text2-2.txt中并在屏幕显示验证。编写的源程序以pgl1302.cpp保存。 提示:文本文件txt2-1.txt可以先采用记事本自行创建并输入自定内容后保存。 训练要点:文件的打开、关闭以及使用字符读写函数对文件读写操作。 程序运行结果参考示例如图11.1.7所示。 .223
要求 2:在源程序 pg11202.cpp 中,为了读出 a2.txt 文件的内容,采用了先关闭再重新打 开该文件的方法。请修改程序,使得只用打开一次文件就完成写入和读出操作。修改结果源 程序以 pg11202b.cpp 保存。 训练要点:使用文件定位函数,如 rewind( )、fseek( )等重置文件位置指针。 修改后程序的运行结果如图 11.1.5 所示。 图 11.1.5 pg11202b.cpp 的运行结果 三、程序编写 1.编写程序,统计一个有多行内容的文本文件 text1.txt 的行数。编写的源程序以 pg11301.cpp 保存。 提示:文本文件 text1.txt 可以先采用记事本自行创建并输入自定内容后保存。 训练要点:文件的打开、关闭以及使用字符写入函数对文件进行写入操作。 程序运行结果参考示例如图 11.1.6 所示。 图 11.1.6 pg11301.cpp 的运行结果 2.编写程序,将一个文本文件 text2-1.txt 中的所有空格去掉后,存放到另外一个文件 text2-2.txt 中并在屏幕显示验证。编写的源程序以 pg11302.cpp 保存。 提示:文本文件 text2-1.txt 可以先采用记事本自行创建并输入自定内容后保存。 训练要点:文件的打开、关闭以及使用字符读写函数对文件读写操作。 程序运行结果参考示例如图 11.1.7 所示。 - 223 -