第十三章 文件
,C语言程序设计,
课程讲义
2006年 4月
上一章节课程回顾
掌握位运算符的使用
了解整数在内存中的存放形式
掌握位运算的应用
负数的补码
首页 上页 下页 节 末页 结束
第 12章 文 件
在程序运行时,程序本身和数据一般都存放在内存中。
当程序运行结束后,存放在内存中的数据被释放。
如果需要长期保存程序运行所需的原始数据,或程序运
行产生的结果,就必须以文件形式存储到外部存储介质上。
12.1 C语言文件概述
12.2 文件的打开与关闭
12.3 文件的读写操作
12.4 位置指针与文件定位
12.5 出错检测
12.1 C语言文件概述
1.文件与文件名
文件是指存放在外部存储介质上的数据集合。
为标识一个文件,每个文件都必须有一个文件名,
其一般结构为,主文件名 [.扩展名 ]
文件命名规则,遵循操作系统的约定。
2.文件分类
可以从不同的角度对文件进行分类,
( 1)根据文件的内容,可分为程序文件和数据文件,
程序文件又可分为源文件、目标文件和可执行文件。
( 2)根据文件的组织形式,可分为顺序存取文件和
随机存取文件。
( 3) 根据文件的存储形式, 可分为 ASCII码文件和二
进制文件 。
ASCII码文件的每 1个字节存储 1个字符, 因而便于
对字符进行逐个处理 。 但一般占用存储空间较多, 而且要
花费转换时间 ( 二进制与 ASCII码之间的转换 ) 。
二进制文件是把内存中的数据, 原样输出到磁盘文件
中 。 可以节省存储空间和转换时间, 但 1个字节并不对应 1
个字符, 不能直接输出字符形式 。
3,读文件与写文件
所谓读文件是指, 将磁盘文件中的数据传送到计算机
内存的操作 。
所谓写文件是指, 从计算机内存向磁盘文件中传送数
据的操作 。
4,构成文件的基本单元与流式文件
C语言将文件看作是由一个一个的字符 ( ASCII码文
件 ) 或字节 ( 二进制文件 ) 组成的 。 将这种文件称为流式
文件 。
而在其它高级语言中, 组成文件的基本单位是记录,
对文件操作的基本单位也是记录 。
5,文件类型 FILE
系统给每个打开的文件都在内存中开辟一个区域, 用
于存放文件的有关信息 ( 如文件名, 文件位置等 ) 。 这些
信息保存在一个结构类型变量中, 该结构类型由系统定义,
取名为 FILE。
注意,结构类型名, FILE”必须大写 。
6,ANSI C的缓冲文件系统
所谓缓冲文件系统是指, 系统自动地在内存
区为每个正在使用的文件开辟一个缓冲区 。
从内存向磁盘输出数据时, 必须首先输出到
缓冲区中 。 待缓冲区装满后, 再一起输出到磁盘
文件中 。
从磁盘文件向内存读入数据时, 则正好相反:
首先将一批数据读入到缓冲区中, 再从缓冲区中
将数据逐个送到程序数据区 。
12.2 文件的打开与关闭
对文件进行操作之前,必须先打开该文件;使用结
束后,应立即关闭,以免数据丢失。
C语言规定了标准输入输出函数库,用 fopen()函数
打开一个文件,用 fclose()函数关闭一个文件。
12.2.1 文件的打开 ──fopen()函数
1,用法,FILE *fopen("文件名 ","操作方式 ");
2,功能:返回一个指向指定文件的指针 。
3,函数原型,stdio.h 。
注,对文件操作的库函数, 函数原型均在头文件
stdio.h中 。 后续函数不再赘述 。
( 1), 文件名, 是指要打开 ( 或创建 ) 的文件名 。
如果使用字符数组 ( 或字符指针 ), 则不使用双引号 。
( 2), 操作方式, 如表 12-1所示 。
例如,FILE *fp;
fp= fopen("data.99","r");
3,说明
( 1) 如果不能实现打开指定文件的操作, 则 fopen()
函数返回一个空指针 NULL ( 其值在头文件 stdio.h中被定
义为0 ) 。
为增强程序的可靠性, 常用下面的方法打开一个文件,
if((fp=fopen("文件名 ","操作方式 "))==NULL)
{ printf("can not open this file\n");
exit(0);
}
● 关于 exit()函数
1) 用法,void exit([程序状态值 ]);
2) 功能:关闭已打开的所有文件, 结束程序运行,
返回操作系统, 并将, 程序状态值, 返回给操作系统 。
当, 程序状态值, 为0时, 表示程序正常退出;非0值
时, 表示程序出错退出 。
( 2), r( b) +”与, a( b) +”的区别:使用前者打
开文件时, 读写位置指针指向文件头;使用后者时, 读
写指针指向文件尾 。
( 3) 使用文本文件向计算机系统输入数据时, 系统
自动将回车换行符转换成一个换行符;在输出时, 将换
行符转换成回车和换行两个字符 。
使用二进制文件时, 内存中的数据形式与数据文
件中的形式完全一样, 就不再进行转换 。
( 4) 有些C编译系统, 可能并不完全提供上述对
文件的操作方式, 或采用的表示符号不同, 请注意所
使用系统的规定 。
( 5) 在程序开始运行时, 系统自动打开三个标准
文件, 并分别定义了文件指针,
1) 标准输入文件 ——stdin:指向终端输入 ( 一
般为键盘 ) 。 如果程序中指定要从 stdin所指的文件输
入数据, 就是从终端键盘上输入数据 。
2) 标准输出文件 ——stdout:指向终端输出
( 一般为显示器 ) 。
3) 标准错误文件 ——stderr:指向终端标准
错误输出 ( 一般为显示器 ) 。
12.2.2 文件的关闭 ──fcolse()函数
1,用法, int fclose(FILE *文件指针 );
2,功能:关闭, 文件指针, 所指向的文件 。
如果正常关闭了文件, 则函数返回值为0;否则,
返回值为非0 。
例如, fclose(fp); /*关闭 fp所指向的文件 */
12.3 文件的读写操作
文件打开之后,就可以对它进行读与写的操作了。
12.3.1 读/写文件中的一个字符
12.3.2 读/写一个字符串
12.3.3 读/写一个数据块
12.3.4 对文件进行格式化读/写
12.3.5 读/写函数的选用原则
[Return]
12.3.1 读/写文件中的一个字符
1.将一个字符写到文件中 ──fputc()函数
[案例 12.1] 将键盘上输入的一个字符串(以,@”作为结束字符),以
ASCII码形式存储到一个磁盘文件中。
/*案例代码文件名,AL13_1.C*/
/*程序功能:从键盘上输入一个字符串,存储到一个磁盘文件中 */
/*使用格式:可执行文件名 要创建的磁盘文件名 */
#include,stdio.h”
main(int argc,char *argv[])
{ FILE *fp;
char ch;
if(argc!=2) /*参数个数不对 */
{ printf("the number of arguments not correct\n\n");
printf(“Usage,可执行文件名 filename \n”);
exit(0);
}
if ((fp=fopen(argv[1],"w"))==NULL) /*打开文件失败 */
{ printf("can not open this file\n");
exit(0);
}
/*输入字符, 并存储到指定文件中 */
for( ; (ch=getchar()) != '@' ; )
fputc(ch,fp); /*输入字符并存储到文件中 */
fclose(fp); /*关闭文件 */
}
程序运行情况,
abcdefg1234567@←┘
库函数 fputc(),
1) 用法,int fputc(字符数据, 文件指针 );
其中, 字符数据,, 既可以是字符常量, 也可以是
字符变量 。
2) 功能:将字符数据输出到, 文件指针, 所指向的
文件中去, 同时将读写位置指针向前移动 1个字节 ( 即
指向下一个写入位置 ) 。
如果输出成功, 则函数返回值就是输出的字符数据;
否则, 返回一个符号常量 EOF( 其值在头文件 stdio.h中,
被定义为 -1) 。
2,从文件中读入一个字符 ──fgetc()函数和 feof()函数
[案例 12.2] 顺序显示 [案例 12.1]创建的磁盘 ASCII码文件 。
/*案例代码文件名,AL13_2.C*/
/*程序功能:顺序显示一个磁盘 ASCII码文件 */
/*参数:带参主函数, 使用格式:可执行文件名 源文件名 */
#include "stdio.h"
main(int argc,char *argv[])
{ FILE *fp;
char ch;
if(argc!=2) /*参数个数不对 */
{ printf("the number of arguments not correct\n");
printf(“\n Usage,可执行文件名 源文件名 ");
exit(0);
}
if ((fp=fopen(argv[1],"r"))==NULL)
{ printf("can not open source file\n");
exit(0);
}
/*顺序输出文件的内容 */
for(; (ch=fgetc(fp))!=EOF; )
putchar(ch); /*顺序读入并显示 */
fclose(fp); /*关闭打开的文件 */
}
程序运行情况,
abcdefg1234567
( 1) 库函数 fgetc()
1) 用法,int fgetc(文件指针 );
2) 功能:从, 文件指针, 所指向的文件中, 读入一
个字符, 同时将读写位置指针向前移动 1个字节 ( 即指
向下一个字符 ) 。 该函数无出错返回值 。
例如, fgetc(fp)表达式, 从文件 fp中读一个字符, 同
时将 fp的读写位置指针向前移动到下一个字符 。
( 2) 关于符号常量 EOF
在对 ASCII码文件执行读入操作时, 如果遇到文件
尾, 则读操作函数返回一个文件结束标志 EOF( 其值在
头文件 stdio.h中被定义为 -1) 。
在对二进制文件执行读入操作时, 必须使用库函数
feof()来判断是否遇到文件尾 。
[案例 12.3] 实现制作 ASCII码文件副本的功能 。
/*案例代码文件名,AL13_3.C*/
/*程序功能:制作 ASCII码文件的副本 */
/*使用格式:可执行文件名 源文件名 目标文件名 */
#include "stdio.h"
main(int argc,char *argv[])
{ FILE *input,*output; /* input:源文件指针,output:目标文件指针 */
char ch;
if(argc!=3) /*参数个数不对 */
{ printf("the number of arguments not correct\n");
printf("\n Usage,可执行文件名 source-file dest-file");
exit(0);
}
if ((fp=fopen(argv[1],"r"))==NULL) /*打开源文件失败 */
{ printf("can not open source file\n");
exit(0);
}
if ((fp=fopen(argv[2],"w"))==NULL) /*创建目标文件失败 */
{ printf("can not create destination file\n");
exit(0);
}
/*复制源文件到目标文件中 */
for( ; (!feof(input)) ; ) fputc(fgetc(input),output);
fclose(input); fclose(output); /*关闭源文件和目
标文件 */
}
库函数 feof(),
1)用法,int feof(文件指针 );
2)功能:在执行读文件操作时,如果遇到文件尾,
则函数返回逻辑真( 1);否则,则返回逻辑假( 0)。
feof()函数同时适用于 ASCII码文件和二进制文件。
例如,!feof(input))表示源文件(用于输入)未结束,
循环继续。
[Return]
12.3.2 读/写一个字符串 ──fgets()和 fputs()
[案例 12.4] 将键盘上输入的一个长度不超过 80的字符串,
以 ASCII码形式存储到一个磁盘文件中;然后再输出到屏
幕上。
/*案例代码文件名,AL13_4.C*/
/*参数:可执行文件名 要创建的磁盘文件名 */
#include "stdio.h"
main(int argc,char *argv[])
{ FILE *fp;
char string[81]; /*字符数组用于暂存输入输出的字符串 */
if(argc>2) /*参数太多, 提示 出错 */
{ printf("Too many parameters… \n\n");
printf("Usage,可执行文件名 filename\n");
exit(0);
}
if(argc= =1) /*缺磁盘文件名, 提示输入 */
{ printf("Input the filename,");
gets(string); /*借用 string暂存输入的文件名 */
argv[1]=(char *)malloc(strlen(string)+1);/*给文件名参数申请内存空
间 */
strcpy(argv[1],string);/*复制文件名到形参中 */
}
if ((fp=fopen(argv[1],"w"))==NULL) /*打开文件失败 */
{ printf("can not open this file\n");
exit(0);
}
/*从键盘上输入字符串, 并存储到指定文件中 */
printf("Input a string,"); gets(string); /*从键盘上输入字符串 */
fputs(string,fp); /*存储到指定文件 */
fclose(fp);
/*重新打开文件, 读出其中的字符串, 并输出到屏幕上 */
if ((fp=fopen(argv[1],"r"))==NULL) /*打开文件失败 */
{ printf("can not open this file\n");
exit(0);
}
fgets(string,strlen(string)+1,fp); /*从文件中读一个
字符串 */
printf("Output the string,"); puts(string); /*将字符串输出到
屏幕上 */
fclose(fp);
}
( 1) 为增强程序的可靠性, 程序中对参数过多的情
况, 提示出错, 并终止程序运行;而遗漏文件名时, 提示
用户输入 。
同时, 为增强程序的人机交互性, 凡是需要用户输
入数据的地方, 都设置提示输入的信息;凡是输出数据的
地方, 都设置输出说明信息 。
( 2) 库函数 fputs()──向指定文件输出一个字符串
1) 用法,int fputs(字符串, 文件指针 );
其中, 字符串, 可以是一个字符串常量, 或字符数组名, 或字
符指针变量名 。
2) 功能:向指定文件输出一个字符串, 同时将读写位置指针向
前移动 strlength( 字符串长度 ) 个字节 。 如果输出成功, 则函数返
回值为0;否则, 为非0值 。
( 3) 库函数 fgets()──从文件中读一个字符串
1) 用法,char *fgets(指针, 串长度 +1,文件指针 );
2) 功能:从指定文件中读入一个字符串, 存入, 字符数组/
指针, 中, 并在尾端自动加一个结束标志 '\0';同时, 将读写位置指
针向前移动 strlength( 字符串长度 ) 个字节 。
如果在读入规定长度之前遇到文件尾 EOF或换行符, 读入即结
束 。
[Return]
12.3.3 读/写一个数据块 ──fread()和 fwrite()
实际应用中, 常常要求 1次读/写 1个数据块 。 为此,
ANSI C 标准设置了 fread( ) 和 fwrite()函数 。
1,用法,
int fread(void *buffer,int size,int count,FILE *fp);
int fwrite(void *buffer,int size,int count,FILE *fp);
2,功能,
fread()──从 fp所指向文件的当前位置开始, 一次读入
size个字节, 重复 count次, 并将读入的数据存放到从
buffer开始的内存中;同时, 将读写位置指针向前移动
size* count个字节 。
其中, buffer是存放读入数据的起始地址 ( 即存放何
处 ) 。
fwrite()──从 buffer开始, 一次输出 size个字节, 重复
count次, 并将输出的数据存放到 fp所指向的文件中;同
时, 将读写位置指针向前移动 size* count个字节 。
其中, buffer是要输出数据在内存中的起始地址 ( 即
从何处开始输出 ) 。
如果调用 fread()或 fwrite()成功, 则函数返回值等于
count。
fread()和 fwrite()函数, 一般用于二进制文件的处理 。
[Return]
12.3.4 对文件进行格式化读/写 ──fscanf()和
fprintf()函数
与 scanf()和 printf()函数的功能相似, 区别在于,fscanf()和
fprintf()函数的操作对象是指定文件, 而 scanf()和 printf()函数的操作
对象是标准输入 ( stdin) 输出 ( stdout) 文件 。
int fscanf(文件指针, "格式符 ",输入变量首地址表 );
int fprintf(文件指针, "格式符 ",输出参量表 );
例如,,....,
int i=3; float f=9.80;
,....,
fprintf(fp,"%2d,%6.2f",i,f);
,....,
fprintf()函数的作用是, 将变量 i按 %2d格式, 变量 f按 %6.2f格式,
以逗号作分隔符, 输出到 fp所指向的文件中,□ 3,□□ 9.80( □ 表示
1个空格 ) 。
[Return]
12.3.5 读/写函数的选用原则
从功能角度来说, fread()和 fwrite()函数可以完成文
件的任何数据读/写操作 。 但为方便起见, 依下列原则
选用,
1,读 /写 1个字符 ( 或字节 ) 数据时:选用 fgetc()和
fputc()函数 。
2,读 /写 1个字符串时:选用 fgets()和 fputs()函数 。
3,读 /写 1个 ( 或多个 ) 不含格式的数据时:选用
fread()和 fwrite()函数 。
4,读 /写 1个 ( 或多个 ) 含格式的数据时:选用
fscanf()和 fprintf()函数 。
[Return]
12.4 位置指针与文件定位
文件中有一个读写位置指针,指向当前的读写位置。每
次读写 1个(或 1组)数据后,系统自动将位置指针移动到
下一个读写位置上。
如果想改变系统这种读写规律,可使用有关文件定位
的函数。
12.4.1 位置指针复位函数 rewind()
1.用法,int rewind(文件指针 );
2.功能:使文件的位置指针返回到文件头。
12.4.2 随机读写与 fseek()函数
对于流式文件,既可以顺序读写,也可随机读写,关键
在于控制文件的位置指针。
所谓顺序读写是指,读写完当前数据后,系统自动将
文件的位置指针移动到下一个读写位置上。
所谓随机读写是指, 读写完当前数据后, 可通过调用
fseek()函数, 将位置指针移动到文件中任何一个地方 。
1,用法,int fseek(文件指针, 位移量, 参照点 );
2,功能:将指定文件的位置指针, 从参照点开始,
移动指定的字节数 。
( 1) 参照点:用 0( 文件头 ), 1( 当前位置 ) 和2
( 文件尾 ) 表示 。
在 ANSI C标准中, 还规定了下面的名字,
SEEK_SET──文件头,
SEEK_CUR──当前位置,
SEEK_END──文件尾
( 2) 位移量:以参照点为起点, 向前 ( 当位移量 >0
时 ) 或后 ( 当位移量 <0时 ) 移动的字节数 。 在 ANSI C
标准中, 要求位移量为 long int型数据 。
fseek()函数一般用于二进制文件 。
12.4.3 返回文件当前位置的函数 ftell()
由于文件的位置指针可以任意移动, 也经常移动,
往往容易迷失当前位置, ftell()就可以解决这个问题 。
1,用法,long ftell(文件指针 );
2,功能:返回文件位置指针的当前位置 ( 用相对
于文件头的位移量表示 ) 。
如果返回值为 -1L,则表明调用出错 。 例如,
offset=ftell(fp);
if(offset= =-1L)printf(“ftell() error\n”);
[Return]
12.5 出错检测
12.5.1 ferror()函数
在调用输入输出库函数时,如果出错,除了函数返
回值有所反映外,也可利用 ferror()函数来检测。
1.用法,int ferror(文件指针 );
2.功能:如果函数返回值为 0,表示未出错;如
果返回一个非 0值,表示出错。
( 1)对同一文件,每次调用输入输出函数均产生一
个新的 ferror()函数值。因此在调用了输入输出函数后,
应立即检测,否则出错信息会丢失。
( 2)在执行 fopen()函数时,系统将 ferror()的值自
动置为 0。
12.5.2 clearerr()函数
1,用法,void clearerr(文件指针 );
2,功能:将文件错误标志 ( 即 ferror()函数的值 ) 和
文 件 结 束 标 志 ( 即 feof() 函数的值 ) 置为 0 。
对同一文件, 只要出错就一直保留, 直至遇到 clearerr()
函数或 rewind()函数, 或其它任何一个输入输出库函数 。
[Return]
文件是程序设计中一个重要的概念。操作系统是以文件为单
位对数据进行管理的,也就是说,如果想找存在外部介质
上的数据,必须先按文件名找到所指定的文件,然后再从
该文件中读取数据。 C语言把文件看作是一个字符序列,
即由一个一个字符的数据顺序组成。根据数据的组织形式,
可分为 ASCII文件和二进制文件。掌握,
1,了解文件的基本概念
2、掌握文件的打开与关闭操作
3、掌握文件的读写操作
4、了解文件的出错检测函数
本章小结
在 C语言,文件由 _____ 。
A)记录组成
B)由数据行组成
C)由数据块组成
D)由字符(字节)序列组成
本题考核了文件的基本概念。正确答案是 D。
课堂同步,做做与练练
【 练 12.1】
试题分析
选择正确的选项,
C语言中文件的存取方式 ___ 。
A)只能顺序存取
B)只能随机存取(或称直接存取)
C)可以顺序存取,也可随机存取
D)只能从文件的开头进行存取
本题考核了文件的几种存取方式。正确答案是 C。
课堂同步,做做与练练
【 练 12.2】
试题分析
选择正确的选项,
课堂同步,课后练习与作业
1、对 C文件操作有些什么特点?
2、什么是文件型指针,通过文件指针访问文件有什么好处。
3、有两个磁盘文件,A”和,B”,各存放一行字母,今要
求把这两个文件中的信息合并(按字母顺序排列),输出
到一个新文件,C”中去。。