第十三章文件《C语言程序设计》2目录•13.1文件的概念•13.2文件的使用•13.3文件的打开与关闭•13.4向文件中写数据•13.5往文件中追加数据•13.6从文件中读取数据•13.7文件的定位•13.8其它读写函数《C语言程序设计》313.1文件的概念•我们在学习Win95和DOS时已经接触到了文件的概念。所谓文件一般指存放在外部存储器中数据的集合。外部存储器包括磁盘(软盘和硬盘)、磁带、光盘等。我们通过文件名来访问某个文件,DOS使用8.3的文件名格式,Win95支持长文件名,文件名可以长达255个字符。•前面各章中我们都是从键盘输入数据,运行结果输出到屏幕上。有时我们需要将运行结果输出到磁盘上保存起来,以后需要时再将数据从磁盘直接输入到计算机内存,这样我们就用到了磁盘文件。《C语言程序设计》4文本文件和二进制文件•C语言将文件看作一个字符(字节)序列,根据数据的组织形式分为文本文件和二进制文件两类。•文本文件中的每一个字节存放一个ASCII码,代表一个字符;•二进制文件则是将数据按内存中的原样(二进制形式)存放在磁盘上。•例如有一个十进制整数54321,它在内存中占两个字节,如图,如果将它输出到文本文件则占5个字节,输出到二进制文件占2个字节。《C语言程序设计》5文本文件和二进制文件••文本文件和二进制文件各有特点,二进制文件占存储空间较小,而文本文件更直观,可以用Win95中的记事本程序或DOS中的TYPE命令直接查看。内存中文本文件00110101001101000011001100110010001100011101010000110001'5''4''3''2''1'二进制文件1101010000110001《C语言程序设计》6缓冲文件系统与非缓冲文件系统–早期的C语言有两种处理文件的方法:一种叫“缓冲文件系统”,一种叫“非缓冲文件系统”。–所谓缓冲文件系统是指:系统自动地在内存中为每一个正在使用的文件开辟一个缓冲区。输出时,程序中的数据先送入缓冲区,装满后才一起输出到磁盘;输入时,先从磁盘读一批数据到缓冲区(充满之),然后逐个将数据送到程序中(赋给变量)。缓冲区的大小因C版本而定,一般为512字节。–所谓非缓冲文件系统是指:系统不自动开辟缓冲区,缓冲区由编程者自己开辟、管理。1983年,ANSIC不再采用非缓冲文件系统,我们也不再作介绍。《C语言程序设计》7•13.2文件的使用•我们使用文件的目的是为了存放数据,因此,对文件的操作主要可以分为两种:读操作和写操作。读操作是从文件中读取数据;写操作是往文件中写数据,包括建立一个新文件、往文件中追加数据、插入数据或修改数据。•C语言中没有专门处理文件的语句,对文件的读写操作都是由库函数来完成的。这些库函数的声明都保存在头文件stdio.h中,因此在程序的头部要加上#includestdio.h。《C语言程序设计》8文件类型•缓冲文件系统中,每个正在被使用的文件都在内存中开辟一个区域,存放有关该文件的信息(如文件名、文件状态、当前位置等)。C语言将这些信息保存在一个结构体变量中,该结构体类型是由系统定义的,取名为FILE(见课本310页)。《C语言程序设计》9•13.3文件的打开与关闭•13.3.1打开文件函数fopen•13.3.2关闭文件函数、检测错误函数《C语言程序设计》1013.3.1打开文件函数fopen•对文件进行读写之前应当“打开”该文件,读写完毕之后应当“关闭”该文件。•ANSIC规定使用fopen函数来打开文件。fopen函数的原型为:–FILE*fopen(char*filename,char*mode);•其中,filename指定要打开的文件名,可以使用字符串常量,也可以使用指向字符串的指针变量;mode表示文件的使用方式(见312页表13.1)。《C语言程序设计》11例子•设有如下文件指针的定义:–File*fp;•那么–fp=fopen(“student.dat”,”w”);•表示以文本方式打开文件student.dat,打开后要往文件中写入数据。•又如:–fp=fopen(“score.dat”,”wb+”);•表示以二进制方式打开文件score.dat,向文件中写入数据后还可以读出文件中的数据。《C语言程序设计》12文件有时打不开•如果打不开文件(原因很多),fopen会返回空指针NULL,我们常用下面的方法打开文件:–if((fp=fopen(“文件名”,“文件使用方式”))==NULL)–{–printf(“无法打开此文件!\n”)–exit(0);/*关闭所有文件,终止此程序。*/–}《C语言程序设计》13说明•1.使用“r”和”r+”时,文件应已经存在。•2.使用“w”和”w+”时,新建一个文件,若磁盘上已有同名文件则被删除。•3.使用“a”和”a+”时,文件应已经存在,原有内容不被删除,位置指针移到文件末尾,可以添加内容。《C语言程序设计》14•4.在读文本文件时,遇到回车(‘\r’==13)换行(‘\n’==10)符,自动转换成一个换行符;写时,反过来,将一个换行符转换成一个回车符和一个换行符(为了可以使用TYPE命令显示其内容)。读写二进制文件则无此转换。•5.在程序开始运行时,系统自动打开三个文件:标准输入设备(键盘)、标准输出设备(显示器)和标准错误输出设备(通常也是显示器),与之对应的文件指针为stdin、stdout和stderr。《C语言程序设计》1513.3.2关闭文件函数、检测错误函数《C语言程序设计》161.关闭文件函数fclose•使用完文件后应当关闭它,系统把缓冲区的内容写回文件,然后将文件指针变量与该文件“脱钩”。•关闭文件使用函数fclose,它的原型为–intfclose(FILE*fp);•该函数关闭fp指向的文件。如果文件正常关闭将返回0值;如果关闭文件失败则返回非0值。例–fp=fopen(“a:name.txt”,”w”);/*打开一个文本文件*/–……/*对文件进行操作*/–fclose(fp);/*关闭该文件*/《C语言程序设计》172.检测错误函数ferror•ferror的原型为–intferror(FILE*fp);•它用于检测文件操作是否发生了错误。若返回0则表示没有出错,非0表示有错。《C语言程序设计》183.检测文件是否结束函数feof•feof的原型为:–intfeof(FILE*fp);•它用于检测位置指针是否到达了文件尾部。•返回0表示位置指针未到达文件尾。•返回非0表示位置指针已到达文件尾。《C语言程序设计》194.清除错误标志和文件结束标志函数clearerr•clearerr的原型为–voidclearerr(FILE*fp);•它用于清除读写文件时出现的错误标志及文件结束标志,即将这两个标志设置成0。《C语言程序设计》20•13.4向文件中写数据–向文件中写入数据可以使用以下函数:–1.fputc函数–2.fwrite函数《C语言程序设计》21•1.fputc函数•fputc的原型为–intfputc(intch,FILE*fp);•此函数会将字符ch写入fp指向的文件。若操作成功则返回ch的值;若操作失败则返回EOF(-1)。•通常用于将一个字符写入一个文本文件。《C语言程序设计》22•2.fwrite函数•函数原型:–unsignedfwrite(void*buffer,unsignedsize,unsignedcount,FILE*fp);•功能:将buffer所指向的内存单元开始的内存区中的每项长度为size字节的count个数据项写到fp指向的文件中。•此函数主要用于二进制文件的写操作,可以将一个数组的数据写入文件中。《C语言程序设计》23•[例13.1]•建立一个文本文件letter.dat,将26个英文大写字母写到文件中。–#includestdio.h–main()–{charch;–FILE*fp;–fp=fopen(letter.dat,w);–if(fp==NULL)《C语言程序设计》24–{–printf(\nCannotopenletter.dat!);–exit(0);–}–for(ch='A';ch='Z';ch++)–fputc(ch,fp);–fputc('\n',fp);–fclose(fp);–}《C语言程序设计》25•[例13.2]•建立一个二进制文件score.dat,存放某班32名同学某门课的成绩(每名同学要求有学号和成绩两个数据项。–#includestdio.h–structstruct_name–{–intnumber;–intscore;–}students[32];–main()《C语言程序设计》26–{–FILE*fp;–inti;–if((fp=fopen(score.dat,wb))==NULL)–{printf(Cannotopenfilescore.dat!\n);–exit(0);–}–for(i=0;i32;i++)scanf(%d%d,&students[i].number,&students[i].score);《C语言程序设计》27–for(i=0;i32;i++)–fwrite(&students[i],sizeof(structstruct_name),1,fp);–fclose(fp);–}•第二个for循环也可以用以下语句实现:–fwrite(students,sizeof(structstruct_name),32,fp);《C语言程序设计》28•13.5往文件中追加数据•若要往文件中追加数据,在打开文件时应将文件的使用方式设为“a”或”ab”,这样的话该文件的位置指针会指向最后一个数据的后面,再用fputc或fwrite即可将数据写到文件的后面。•fputc和fwrite除了有写入数据的功能,还会将位置指针向后移动一个位置,为下一次读写操作做准备。《C语言程序设计》29•[例13.3]•设文件letter.dat(26个英文字母)已经由例13.1建立完毕,编写一个程序,要求键盘输入一组字符(直到输入字符‘?’时结束),将这些字符追加到文件的尾部。–#includestdio.h–main()–{–charch;–FILE*fp;–if((fp=fopen(letter.dat,a))==NULL)《C语言程序设计》30–{–printf(Cannotopenthisfile!\n);–exit(0);–}–scanf(%c,&ch);–while(ch!='?')–{–fputc(ch,fp);–scanf(%c,&ch);–}–fclose(fp);–}《C语言程序设计》31•13.6从文件中读取数据•前面介绍了如何往文件中写数据,本节介绍如何从文件中读取数据。《C语言程序设计》32•1.fgetc函数•fgetc的原型为–intfgetc(FILE*fp);•功能:–从文件的当前位置读出一个字符–将位置指针下移一个字符•若读取成功则返回所读的字符;若发生错误或文件结束则返回EOF(-1)。《C语言程序设计》33•2.fread函数•fread的原型为–unsignedfread(void*buffer,unsignedsize,unsignedcount,FILE*fp);•功能:从文件中读取每项长度为size字节的count个数据项,存到buffer所指向的内存单元开始的内存区中。《C语言程序设计》34•[例13.4]•将letter.dat文件存放的所有字符从显示器上显示出来。由于我们不知道文件中目前的字符个数,因此可以用EOF作为循环的结束条件。–#includestdio.h–main()–{–charch;–FILE*fp;–if((fp=fopen(letter.dat,r))==NULL)–{–printf(Cannotopenletter.dat!\n);《C语言程序设计》35–exit(0);–}–if((