第九章 文件
★ 内容提要:
文本文件与二进制文件
缓冲文件系统概念
文件的指针
文件的打开与关闭
文件应用
? 文件分类
? 缓冲文件系统
? 文件的指针
? 文件打开与关闭
? 文件应用
第 九 章 文件
文件是指存储在外部介质
上,且按文件名访问的一组
信息序列。
一、文件分类
? 文本文件(字符代码文件或 ASCII 代码文件)
由一个一个字符组成,每一个字符用一个
ASCII 代码表示,如 1 2 3, 4 5 以 ASCII 代码形式
存储到磁盘需要 6 个字节。
特点,可通过显示器或打印机显示,即可读,
比较直观。
一、文件分类
? 非文本文件(二进制文件 ),是指以数据
在内存中的存储形式原样输出存储到磁 盘上的
文件。如 123.45 在内存中以浮点数形式存储占
4 个字节,不管一个实数多大都占 4 字节。
特点,节省存储空间,输入输出无需转换
速度快,不便阅读。
说明:
? 一个 C 文件是一个字节流或二进制流,它把
数据看作是一连串的字符 序列(字节),而不
考虑记录的界限,即 C 文件并不是由记录组成的。
? 由于对文件的操作要与各种外部设备发生联
系,因此对文件的输入输出(读写)过程是通
过操作系统来实现的。对文件的读写都是通过
标准的 I/O 函数进行的。
二、缓冲文件系统 ( 标准 I/O ) 和非缓冲文件系统
? 缓冲文件系统(又称标准或高层文件系统)
特点, 对程序中的每一个文件都在内存中开辟
一个, 缓冲区, 。
作用, 从磁盘文件读入的数据先送到, 输入缓
冲区, 中,然后再从缓冲区依次将数据送给接
收变量。
在向磁盘文件输出数据时,先将程序数据区中变量
或表达式的值送到, 输出文件缓冲区, 中,待装满后
才一起输出给磁盘文件。目的 减少对磁盘的读写次数,
即一次可以读入一批数据或输出一批数据。
输 入 文 件 缓 冲 区
(51 2 K B)
输 出 文 件 缓 冲 区
(51 2 K B)
变量 a
程序数据区
磁盘
文件
读
写
内存
二、缓冲文件系统 ( 标准 I/O ) 和非缓冲文件系统
? 非缓冲文件系统,不由系统自动设置所需
缓冲区,而由用户自己根据需要设置。
? 新的 A NS I 标准只建议使用缓冲系统,并对
缓冲文件系统的功能进行了扩充,使既能用于
处理字符代码文件,也能处理二进制文件。
三、文件型指针类型
对文件的操作是通过文件指 针实现的。关键
的概念是, 文件指针, 。
调用一个文件需要的信息:
? 文件当前读写的位置;
? 与该文件对应的内存缓冲区的地址;
? 缓冲区未被处理的字符数 ( 字符指针 ) ;
? 文件的操作方式等
三、文件型指针类型
系统内部定义了一个称 FILE 的结构型类型。
typedef struct{
int _fd; // 文件号
int _cleft; // 缓冲区中剩余的字符
int _mode; // 文件操作模式
char *_nextc; // 下一个字符位置
char *_buff; // 文件缓冲区位置
} FILE;
四、文件的打开和关闭
文件必须先打开后,并及时关闭。
1, 打开文件,是在用户程序和操作系统之
间建立起联系,程序要把操作的文件的 一些信
息通知操作系统,如文件 名、文件操作方式
(读 / 写):
读文件, 需要先确认此文件是否已存在,并
将读当前位置设定为文件的开头。
写文件, 需要检查原来是否有同名文件,如
有则将该文件原有内容删除,如无同 名文件就
建立一个新文件,然后将写当前位置 设定于文
件的开头,以便从文件开头写入数据。
1,文件的打开方式,
FILE *fp;
if((fp=fopen(" 文件名 "," 使用文件方式 "))== NULL){
printf("cannot open this file,\ n");
exit(0);
}
说明:
? 文件名可以是字符串常量、数组名或字符指针。
? 使用文件方式参见附表。
FILE *fp;
if((fp=fopen(" 文件名 "," 使用文件方式 "))== NULL){
printf("cannot open this file,\ n"); exit(0);
}
文件输入 / 输出
缓冲区
… … … … …
……………
用户程序与数据区
磁盘
文件
读 / 写
内存
fp
_ fd 文件号
_ cleft 缓冲区中剩余
的字符
_ mode 文件操作方式
*_ nextc 下一个字符位
置(指针)
*_ buff 文件缓冲区位
置(指针)
FILE 相应的结构变量
程序与外部
文件的联接
示意图,具
体操作由文
件管理系统
负责
… … … … …
读 写
下一个字符位
置(指针)
文件缓冲区位
置(指针)
程序与外部
文件的联接
示意图,具
体操作由文
件管理系统
文件使用方式 含 义
r ( 只读)
w ( 只写)
a ( 追加)
rb ( 只读)
wb ( 只写)
ab ( 追加)
r+ ( 读写)
w+ ( 读写)
a+ ( 读写)
rb+ ( 读写)
wb+ ( 读写)
ab+ ( 读写)
为输入打开一个字符文件
为输出打开一个字符文件
向字符文件尾部增补数据
为输入打开一个二进制文件
为输出打开一个二进制文件
向二进制文件尾部增补数
为读 / 写打开一个字符文件
为读 / 写建立一个新的字符文件
为读 / 写打开一个字符文件
为读 / 写打开一个二进制文件
为读 / 写建立一个新的二进制文件
为读 / 写打开一个二进制文件
2,文件的关闭
文件的关闭形式:
fclose (fp) ;
功能:将 fp 所指文件关闭。
? 释放文件有关信息区;
? 将输出文件缓冲区的内容(无论缓冲区是否为满)
都输出写入文件,然后关闭文件,这样可防止 丢
失本来应写入文件的数据。
五、文件应用示例
[ 例 1],格式化的输入输出。
fp ri nt f( fp,格式字符串,输出项表列 )
功能,将输出按格式串规定输出到 fp 所指文件 。
fscanf( fp,格式字符串,输入项表列 )
功能, 从 fp 所指文件按格式串读入数据。函数执行成功
返回读得的数据项个数;若在读第一项前已到达文件
结束处,则返回 EOF 。
# include <stdio.h>
#include <process.h>
#include <string.h>
void main(){
FILE *fp; char name[10]; int num; float score;
if((fp=fopen("file3.txt","w+"))==NULL){
printf("cannot open this file, \ n");
exit(0);
}
printf("enter name,num,score:");
scanf("%s %d %f",name,&num,&score);
while(strlen(name)>1){
fprintf(fp,"%s %d %f \ n",name,num,score);
printf("enter name,num,score:");
scanf("%s %d %f",name,&num,&score);
}
rewind(fp);
while(fscanf(fp,"%s %d %f",
name,&num,&score)!=EOF)
printf("% - 10s %6d %6.2f \ n",name,num,score);
fclose(fp);
}
输入,enter name,num,score,zhangsan 0501 90 ↙
enter name,num,score,liming 0502 85 ↙
enter name,num,score,gaofei 0503 95 ↙
enter name,num,score,0 0 0 ↙
输出,zhangsan 0501 90.00
liming 0502 85.00
gaofei 0503 95.00
[ 例 2],数据块(二进制形式)的读写。
frea d( b uffer,siz e,c ount,fp)
功能, 从指定文件读入 count 个大小为 si z e 的字
节数据块,存入 b uf f e r 所指存储单元。返回所
读的数据项个数,如遇文 件结束或出错返回 0 。
fwrite( buffer,siz e,c ount,fp)
功能, bu f f e r 所 指 存 储 单 元 的 数 据 取
size*count 个字节送 fp 所指文件。返回写到 fp
所指文件中的数据项个数。
[ 例 2],数据块(二进制形式)的读写。
frea d( b uffer,siz e,c ount,fp)
fwrite( buffer,siz e,c ount,fp)
说明:
? buffer 为输入输出在内存中存放的首地址。
? size 为读、写的字节数,即数据块的大小。
? count 为输入输出的数据项个数。
? f r e a d () 和 fwrite() 用于二进制文件的输入
输出
# include <stdio.h>
#include <process.h>
#define SIZE 4
struct student{
char name[10]; int num,age; char addr[15];
}stud[SIZE];
void save_load(){
FILE *fp; int i;
if((fp=fopen("stu_list","wb+"))==NULL){
printf("cannot open file,\ n"); exit(0);
}
for(i=0; i<SIZE; i++)
if(fwrite(&stud[i],sizeof(struct student),1,fp)!=1){
printf("file write error! \ n"); exit(0);
}
rewind(fp);
for(i=0; i<SIZE; i++)
if(fread( &stud[i],sizeof(struct student),1,fp)!=0 )
printf("% - 10s %4d %4d % - 15s \ n",stud[i].name,
stud[i].num,stud[i].age,stud[i].addr);
}
void main(){
int i;
for(i=0; i<SIZE; i++)
scanf("%s %d%d%s",stud[i].name,&stud[i].num,
&stud[i].age,stud[i].addr);
save_load();
}
输入:
zhang 1001 19 room_101 ↙
li 1002 20 room_102 ↙
wang 1003 21 room_103 ↙
zhao 1004 21 room_104 ↙
输出:
zhang 1001 19 room_101
li 1002 20 room_102
wang 1003 21 room_103
zhao 1004 21 room_104
[ 例 3],具有文件拷贝功能的程序 f i l e co p y, c
说明两个问题,命令行参数的应用和文件的字
符输入与输出应用。
fgetc( fp )
功能, 从指定文件读入一个字符。
fpu tc( ch,fp )
功能, 把一个字符写到指定文件中去。
# include <stdio.h>
#include <process.h>
#include <string.h>
filecopy(FILE *fp1,FILE *fp2){
char c;
while((c=fgetc(fp1))!=EOF)
fputc(c,fp2);
}
[ 例 3],具有文件拷贝功能的程序 f i l e co p y, c
void main(int argc,char *argv[]){
filecopy(FILE *fp1,FILE *fp2) ;
FILE *fp1,*fp2;
if(argc>1){
if((fp1=fopen(*++argv,"r"))==NULL){
printf("can \ 't fopen %s \ n",*argv); exit(0);
}
if((fp2=fopen(*++argv,"w"))==NULL){
printf("can \ 't fopen %s \ n",*argv); exit(0);
}
filecopy(fp1,fp2);
}
}
运行时情况:
$ vi filecopy.c ↙
$cc file.c – o filecopy ↙
$ filecopy t.c t1.c ↙
fiecopy \ 0
t.c \ 0
t1.c \ 0
argv[0]
argv[1]
argv[2]
argv[]
3
argc
运行时数据状态:运行时数据状态:
fgets( str,n,fp ) 字符串输入函数。
? 其功能是从 fp 指定的文件中读取一个串,若满足 以
下条件读取结束,① 已读取 n - 1 个字符, ② 当前读取
到的字符是回车符, ③ 已读取到文件尾。
? 读取的字符个数至多 n - 1 个,余下的一个字节空间作
为加 ‘ \ 0 ’ 串结束符。
? 读取回车符时,也作为一个字符送入由 str 所指的内
存 缓冲区。然后再加一个字符串结束符 ‘ \ 0 ’
? str 为数组名或字符指针; n 为读取字符个数。
[ 例 4],文件的字符串的输入输出处理
fpu ts(str,fp) 字符串输出(写)函数
? 其功能是将 str 所指定的字符串写到 fp 指向的文件中。
? 与 fgets() 函数在输入字符串末尾自动加 ‘ \ 0 ’ 特性
对应,f p u ts ( ) 函数在将 C 字符串写入文件时,其末尾
的 ‘ \ 0 ’ 字符自动舍去。
? fputs() 与 puts() 功能不同,f p u ts ( ) 舍去串结束符
而 puts() 把它转换成回车符输出。
[ 例 4],文件的字符串的输入输出处理
# include <stdio.h>
#include <process.h>
#include <string.h>
void main(){
FILE *fp; char str[16];
if((fp=fopen("file2.txt","w"))==NULL){
printf("cannot open this file,\ n"); exit(0);
}
while(strlen(gets(str))>0) fputs(str,fp);
fclose(fp);
if((fp=fopen("file2.txt","r"))==NULL){
printf("cannot open this file,\ n"); exit(0);
}
while(fgets(str,16,fp)!=NULL)
printf("%s \ n",str);
fclose(fp);
}
输入,aaaaaaaaaaaaaaa ↙
bbbbbbbbbbbbbbb ↙
ccccccccccccccc ↙
输出,aaaaaaaaaaaaaaa
bbbbbbbbbbbbbbb
ccccccccccccccc
# include <stdio.h>
#include <math.h>
#define EPS 1e - 7
void main(){
double udf_sin(double x); // 用户自定义函数原型说明
double a; scanf("%lf",&a);
printf("%f %f \ n",udf_sin(a),sin(a));
}
double udf_sin( double x ){ // 用户自定义函数
double sum,term,n=1; sum=term=x;
while( fabs(term) > EPS ){
n=n+1;
term=term*( - x*x)/((2*n - 2)*(2*n - 1));Th e end
培 育 英 才 钻 研 科 学
书山有径勤为路
学海无边苦作舟
书山有径勤为路书山有径勤为路
学海无边苦作舟学海无边苦作舟