第十三章 文 件
C文件概述文件是存储在外部介质上数据的集合文件是操作系统数据管理的单位使用数据文件的目的数据文件的改动不引起程序的改动 ——程序与数据分离不同程序可以访问同一数据文件中的数据 ——数据共享能长期保存程序运行的中间数据或结果数据按文件的逻辑结构:
记录文件 --由具有一定结构的记录组成(定长 /不定长

流式文件 --由一个个字符(字节)数据顺序组成按存储介质:
普通文件 --存储介质文件(磁盘、磁带等)
设备文件 --非存储介质(键盘、显示器、打印机等)
按数据的组织形式:
文本文件 --ASCII文件,每个字节存放一个字符的
ASCII码二进制文件 --数据按其在内存中的存储形式原样存放文件分类如 int型数 10000
0010011100010000
内存存储形式
0010011100010000
二进制形式
0011000100110000001100000011000000110000
ASCII形式文本文件特点,
存储量大、速度慢、便于对字符操作二进制文件特点,
存储量小、速度快、便于存放中间结果缓冲文件系统:高级文件系统,系统自动为正在使用的文件开辟内存缓冲区磁盘文件输出文件缓冲区输入文件缓冲区程序数据区
a
缓冲文件系统:
文件处理方法非缓冲文件系统:低级文件系统,由用户在程序中为每个文件设定缓冲区缓冲区指令区程序用户数据区 磁盘非缓冲文件系统:
文件结构体 FILE
缓冲文件系统为每个正使用的文件在内存开辟文件信息区文件信息用系统定义的名为 FILE的结构体描述
FILE定义在 stdio.h中
typedef struct
{ int _fd; //文件号
int _cleft; //缓冲区中剩下的字符数
int _mode; //文件操作方式
char *_next; //文件当前读写位置
char *_buff; //文件缓冲区位置
}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;
指针变量说明,FILE *fp;
文件打开时,系统自动建立文件结构体,并把指向它的指针返回来,程序通过这个指针获得文件信息,访问文件。
文件关闭后,它的文件结构体被释放。
文件名文件使用方式文件类型指针
C程序 操作系统磁盘文件类型指针
C语言没有输入输出语句,文件操作用库函数实现,包含在头文件 stdio.h中文件使用方式,打开文件 -->文件读 /写 -->关闭文件文件的打开与关闭函数原型,FILE *fopen(char *name,char *mode)
打开文件 fopen 要打开的文件名 使用文件方式功能:按指定方式打开文件返回值:正常打开,为指向文件结构体的指针;打开失败,为 NULL
“r+/rb+” (读写 )
“a/ab” (追加 )
“w/wb” (只写 )
“r/rb” (只读 )
“w+/wb+” (读写 )
“a+/ab+” (读写 )
为输入打开一个文本 /二进制文件为输出打开或建立一个文本 /二进制文件为读 /写打开一个文本 /二进制文件为读 /写建立一个文本 /二进制文件为读 /写打开或建立一个文本 /二进制文件向文本 /二进制文件尾追加数据文件使用方式 含义例 FILE *fp;
fp= fopen (“c:\\test.dat”,”r”);
例 FILE *fp;
char *filename=“c:\\test.dat”
fp= fopen(filename,”r”);
例 文件打开与测试
FILE *fp = fopen(“test.c”,“w”);
if(fp==NULL)
{ printf(“File open error!\n”);
exit(0);
}
“r+/rb+” (读写 )
“a/ab” (追加 )
“w/wb” (只写 )
“r/rb” (只读 )
“w+/wb+” (读写 )
“a+/ab+” (读写 )
为输入打开一个文本 /二进制文件为输出打开或建立一个文本 /二进制文件为读 /写打开一个文本 /二进制文件为读 /写建立一个文本 /二进制文件为读 /写打开或建立一个文本 /二进制文件向文本 /二进制文件尾追加数据文件使用方式 含义说明:
用 r方式打开的文件,只能用于输入,并且文件必须已经存在;
用 w方式打开的文件,只能用于输出,如果文件不存在,
则在打开时新建一个同名文件;
要向文件末尾添加数据,则用 a方式打开,但该文件必须已经存在;
用 r+,w+,a+方式打开的文件既可以用来输入也可以用来输出;
不能打开则会返回一个 NULL指针;
作用,使文件指针变量与文件“脱钩”,释放文件结构体和文件指针函数原型,int fclose(FILE *fp)
功能:关闭 fp指向的文件返值:正常关闭为 0; 出错时,非 0
文件打开时返回的文件类型指针文件关闭 fclose
不关闭文件可能会丢失数据磁盘文件输出文件缓冲区输入文件缓冲区程序数据区
a
缓冲文件系统:
fclose
字符 I/O:fputc与 fgetc
fputc
函数原型,int fputc (int ch,FILE *fp)
功能:把一字节代码 ch写入 fp指向的文件中返回值:正常,返回 ch; 出错为 EOF
fgetc
函数原型,int fgetc (FILE *fp)
功能:从 fp指向的文件中读取一字节代码返回值:正常,返回读到的代码值 ;
读到文件尾或出错,为 EOF
文件的读写例,从键盘输入字符,逐个存到磁盘文件中,直到 输入
‘ #“为止
#include <stdio.h>
void main()
{ FILE *fp;
char ch,*filename="out.txt";
if((fp=fopen(filename,"w"))==NULL)
{ printf("cannot open file\n");
exit(0);
}
printf("Please input string:");
ch=getchar();
while(ch!='#')
{ fputc(ch,fp);
putchar(ch);
ch=getchar();
}
fclose(fp);
}
例,读文本文件内容并显示
#include <stdio.h>
main()
{ FILE *fp;
char ch,*filename="out.txt";
if((fp=fopen(filename,"r"))==NULL)
{ printf("cannot open file\n");
exit(0);
}
while((ch=fgetc(fp))!=EOF)
putchar(ch);
fclose(fp);
}
判断文本文件是否结束
feof
函数原型,int feof(FILE *fp)
功能:判断文件是否结束返回值:文件结束,返回真(非 0);文件未结束,返回 0
判断二进制文件是否结束
while(!feof(fp))
{ c=fgetc(fp);
……..
}
main()
{ FILE *in,*out;
char ch,infile[10],outfile[10];
scanf("%s",infile);
scanf("%s",outfile);
if ((in = fopen(infile,"r"))== NULL)
{ printf("Cannot open infile.\n");
exit(0);
}
if ((out = fopen(outfile,"w"))== NULL)
{ printf("Cannot open outfile.\n");
exit(0);
}
while (!feof(in))
fputc(fgetc(in),out);
fclose(in); fclose(out);
}
例,文件复制数据块 I/O:fread与 fwrite
函数原型:
size_t fread(void *buffer,size_t size,size_t count,FILE *fp)
size_t fwrite(void *buffer,size_t size,size_t count,FILE *fp)
功能:读 /写数据块返值:成功,返回读 /写的块数;出错或文件尾,返回 0
说明:
typedef unsigned size_t;
buffer,指向要输入 /输出数据块的首地址的指针
size,每个要读 /写的数据块的大小(字节数)
count,要读 /写的数据块的个数
fp,要读 /写的文件指针
fread与 fwrite 一般用于二进制文件的输入 /输出例 float f[2];
FILE *fp;
fp=fopen(“in.dat","rb");
fread(f,4,2,fp);
for(i=0;i<2;i++)
fread(&f[i],4,1,fp);
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score[3];
}stud[10];
for(i=0;i<10;i++)
fread(&stud[i],sizeof(struct student),1,fp);
例,从键盘输入 2个学生数据,把他们转存到磁盘文件中去
#define SIZE 2
struct student_type
{ char name[10];
int num;
int age;
char addr[15];
}stud[SIZE];
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();
display();
}
void save()
{ FILE *fp;
int i;
if((fp=fopen(" c:\\stu_dat","wb"))==NULL)
{ printf("cannot open file\n");
return;
}
for(i=0;i<SIZE;i++)
if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)
printf("file write error\n");
fclose(fp);
}
void display()
{ FILE *fp;
int i;
if((fp=fopen("c:\\stu_dat","rb"))==NULL)
{ printf("cannot open file\n");
return;
}
for(i=0;i<SIZE;i++)
{ fread(&stud[i],sizeof(struct student_type),1,fp);
printf("%-10s %4d %4d %-15s\n",stud[i].name,
stud[i].num,stud[i].age,stud[i].addr);
}
fclose(fp);
}
格式化 I/O:fprintf与 fscanf
函数原型:
int fprintf(FILE *fp,const char *format[,argument,…])
int fscanf(FILE *fp,const char *format[,address,…])
功能:按格式对文件进行 I/O操作返值:成功,返回 I/O的个数 ;出错或文件尾,返回 EOF
例,
fprintf(fp,“%d,%6.2f”,i,t);
//将 i和 t按 %d,%6.2f格式输出到 fp文件
fscanf(fp,“%d,%f”,&i,&t);
//若文件中有 3,4.5,则将 3送入 i,4.5送入 t
main()
{ char s[80],c[80];
int a,b;
FILE *fp;
if((fp=fopen("test","w"))==NULL)
{ puts("can't open file"); exit() ; }
scanf("%s%d",s,&a); /*read from keaboard*/
fprintf(fp,"%s %d",s,a); /*write to file*/
fclose(fp);
if((fp=fopen("test","r"))==NULL)
{ puts("can't open file"); exit(); }
fscanf(fp,"%s%d",c,&b); /*read from file*/
printf("%s %d",c,b); /*print to screen*/
fclose(fp);
}
例,从键盘按格式输入数据存到磁盘文件中去字符串 I/O,fgets与 fputs
函数原型:
char *fgets(char *s,int n,FILE *fp)
fgets从 fp所指文件读 n-1个字符送入 s指向的内存区,并在最后加一个‘ \0’ (若读入 n-1个字符前遇换行符或文件尾 EOF
即结束 )
int fputs(char *s,FILE *fp)
fputs把 s指向的字符串写入 fp指向的文件返回值:
fgets正常时返回读取字符串的首地址;出错或文件尾,
返回 NULL;
fputs正常时返回 0;出错为 EOF。
例:
从键盘读入字符串存入文件,
再从文件读回显示
main()
{ FILE *fp;
char string[81];
if((fp=fopen("file.txt","w"))==NULL)
{ printf("cann't open file");exit(0); }
if(strlen(gets(string))>0)
{ fputs(string,fp);
fputs("\n",fp);
}
fclose(fp);
if((fp=fopen("file.txt","r"))==NULL)
{ printf("cann't open file");exit(0); }
if(fgets(string,81,fp)!=NULL)
puts(string);
fclose(fp);
}
读/写函数的选用原则从功能角度来说,fread()和 fwrite()函数可以完成文件的任何数据读/写操作 。 但为方便起见,依下列原则选用:
读 /写 1个字符 ( 或字节 ) 数据时:选用 fgetc()和 fputc()
函数 。
读 /写 1个字符串时:选用 fgets()和 fputs()函数 。
读 /写 1个 ( 或多个 ) 不含格式的数据时:选用 fread()和
fwrite()函数 。
读 /写 1个 ( 或多个 ) 含格式的数据时:选用 fscanf()和
fprintf()函数 。
几个概念文件位置指针 -----指向当前读写位置的指针读写方式顺序读写:位置指针按字节位置顺序移动随机读写:位置指针按需要移动到任意位置
rewind函数函数原型,void rewind(FILE *fp)
功能:重置文件位置指针到文件开头返值:无文件的定位例,对一个磁盘文件进行显示和复制两次操作
#include <stdio.h>
main()
{ FILE *fp1,*fp2;
fp1=fopen("file1.txt ","r");
fp2=fopen("file2.txt ","w");
while(!feof(fp1)) putchar(fgetc(fp1));
rewind(fp1);
while(!feof(fp1)) fputc(fgetc(fp1),fp2);
fclose(fp1);
fclose(fp2);
}
函数原型,int fseek(FILE *fp,long offset,int whence)
功能:改变文件位置指针的位置返值:成功,返回 0;失败,返回非 0值位移量(以起始点为基点,移动的字节数 )
>0 向后移动; <0 向前移动起始点文件开始 SEEK_SET 0
文件当前位置 SEEK_CUR 1
文件末尾 SEEK_END 2
例 fseek(fp,100L,0);
fseek(fp,50L,1);
fseek(fp,-10L,2);
ftell函数函数原型,long ftell(FILE *fp)
功能:返回位置指针当前位置 (相对文件开头的位移量 )
返值:成功,返回当前位置指针位置;失败,返回 -1L
fseek函数例,磁盘文件上有 3个学生数据,要求读入第 1,3学生数据并显示
main()
{ int i;
FILE *fp;
if((fp=fopen("stu_dat","rb"))==NULL)
{ printf("can't open file\n");exit(0); }
for(i=0;i<=2;i+=2)
{ fseek(fp,i*sizeof(struct student_type),0);
fread(&stud[i],sizeof(struct student_type),1,fp);
printf("%s %d %d %s\n",
stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
}
fclose(fp);
}
#include <stdio.h>
struct student_type
{ int num;
char name[10];
int age;
char addr[15];
}stud[3];
main()
{ FILE *fp;
char filename[80];
long length;
gets(filename);
fp=fopen(filename,"rb");
if(fp==NULL)
printf("file not found!\n");
else
{ fseek(fp,0L,SEEK_END);
length=ftell(fp);
printf("Length of File is %1d bytes\n",length);
fclose(fp);
}
}
例:求文件长度
ferror函数函数原型,int ferror(FILE *fp)
功能:测试文件是否出现错误返值:未出错,0; 出错,非 0
说明每次调用文件输入输出函数,均产生一个新的
ferror函数值,所以应及时测试
fopen打开文件时,ferror函数初值自动置为 0
出错的检测函数原型,void clearerr(FILE *fp)
功能:使文件错误标志置为 0
返值:无说明:出错后,错误标志一直保留,直到对同一文件调
clearerr(fp)或 rewind或任何其它一个输入输出函数
clearerr函数例,ferror()与 clearerr()举例
#include <stdio.h>
int main(void)
{ FILE *stream;
stream = fopen("DUMMY.FIL","w");
getc(stream);
if (ferror(stream))
{ printf(“Error reading from DUMMY.FIL\n");
clearerr(stream);
}
if(!ferror(stream))
printf("Error indicator cleared!");
fclose(stream);
return 0;
}