Presentation is loading. Please wait.

Presentation is loading. Please wait.

11.1 文件的基本概念 11.2 文件的打开与关闭 11.3 文件的顺序读写 11.4 文件的随机读写 11.5 文件检测

Similar presentations


Presentation on theme: "11.1 文件的基本概念 11.2 文件的打开与关闭 11.3 文件的顺序读写 11.4 文件的随机读写 11.5 文件检测"— Presentation transcript:

1 11.1 文件的基本概念 11.2 文件的打开与关闭 11.3 文件的顺序读写 11.4 文件的随机读写 11.5 文件检测 11.6 程序综合举例

2 【本章要点】 文件在计算机领域中是一个重要概念,其实质是存储在计算机外存上的一组相关信息的集合。文件的名字是唯一的,并且作为其本身的操作标志。与任何程序设计语言一样,C语言也提供了强大的机制来支持对文件的各类操作。本章内容围绕着二进制文件与文本文件的操作展开,具体阐述了对它们的基本操作方法,对文件的读出与写入,以及对文件的错误检测等做作初步介绍。

3 11.1 文件的基本概念 文件的概念 文件(File):存放在外部介质(如计算机硬盘、软件、光盘、优盘等)上的一组完整信息的集合。这些信息可为各国文字、图形、图像、电影、音乐、电子小说,甚至包括病毒程序等。

4 11.1 文件的基本概念 11.1.2 文件名称 文件名:是引用文件的唯一的标识符。 文件名包括三个要素:
文件名称 文件名:是引用文件的唯一的标识符。 文件名包括三个要素: ⑴文件路径,是指文件在外部存储器设置中的位置,路径一般以分隔符“\”来体现存储位置的嵌套层次;如D:\Program\TC\Example。 ⑵文件主名,命名规则遵循标识符的命名规则。 ⑶文件扩展名(或称文件后缀),在文件主名之后,以“.”符号分隔。用来反映文件的类型或性质。

5 11.1 文件的基本概念 11.1.2 文件名称 常用文件扩展名 文件扩展名 文件的性质或类型 .c C语言源程序文件 .cpp
文件名称 文件扩展名 文件的性质或类型 .c C语言源程序文件 .cpp TC 3.0语言源程序文件 .bas Basic语言源程序文件 .txt 纯文本文件 .dat 数据文件 .doc Word文件 .mdb Access数据库文件 .exe 可运行的程序文件 .com 可执行的命令文件 .bmp 位图图形文件 .jpg 压缩格式的图形文件 .avi 微软公司开发的视频格式文件 .mp3 压缩的音乐文件 常用文件扩展名

6 11.1 文件的基本概念 两种重要的文件类型 ⑴ 文本文件(Text File),也称为ASCⅡ文件。每一个字节存储一个ASCⅡ码形式表示的字符。文本文件是可直接阅读的,使用Word或Windows的记事本打开即可看到文件的内容。扩展名为.txt的文件。 ⑵ 二进制文件(Binary File)。这类文件将文件中的数据按照它的二进制编码的形式存储。由于这类文件内容是二进制编码,因而它无法直接使用记事本或Word打开阅读。一般的可执行程序都为二进制文件,如扩展名为.exe或.com的文件即为二进制文件。

7 11.1 文件的基本概念 两种重要的文件类型 例如:有一个整型数据123,在两种文件中的存放形式分别如图11.1、图11.2所示。 图11.1 在二进制文件中的存放形式 图11.2 在文本文件中的存放形式

8 11.1 文件的基本概念 11.1.3 两种重要的文件类型 文本文件与二进制文件的优缺点:
两种重要的文件类型 文本文件与二进制文件的优缺点: 文本文件的优点:字符输出的操作中不需转换直接输出,十分方便。 文本文件的缺点:一个字符占一个字节,文件占用的存储空间较多,读写时需要转换,访问的时空效率不高。 二进制文件的优点:二进制文件中的数据与数据的在内存中的表示形式一致。占单元数与操作系统和数据类型有关。二进制文件在存储数据时非常紧凑,占用存储空间较少;在读写时不需进行转换,具有较高的时空效率。 二进制文件的缺点:二进制文件无法直接以字符形式输出,必须要经过一个转换过程。

9 11.1 文件的基本概念 文件的缓冲机制 文件缓冲机制:当程序读取文件内容时,系统先将外部文件中的一批批的数据放入一个文件缓冲区内,当文件缓冲区中的数据达到一定数量后,才一次性地将这些数据输入到程序的数据区;反过来,当程序向文件写入数据时,文件缓冲机制也是先将数据写入到文件缓冲区中,当数据写完或缓冲区写满时,才会一次性地将这些数据写入到文件所在的外部设备中。 文件缓冲区:计算机系统为要处理的文件在内存中单独开辟出来的一个存储区间,在读写该文件时,做为数据交换的临时“存储中转站”。 文件缓冲机制的原理见下图。 引入文件缓冲机制的好处就是:能够有效地减少对外部设备(如磁盘、打印机等)的频繁访问,减少内存与外设间的数据交换,添补内、外设备的速度差异,提高数据读写的效率。

10 11.1 文件的基本概念 FILE指针 文件指针:C语言系统对文件的操作必须通过一个指向“FILE类型”的指针来实现,我们称这种指针为 “文件指针”。 FILE类型:是C语言系统定义的一种标准类型,它实质上是一个结构体。该结构体中定义了一组域,用来保存与文件相关的重要信息。不同的C语言系统对“FILE类型”的描述会略有不同,但基本信息是一致的。 对文件的操作要通过定义一个指向FILE类型的文件指针变量来实现对文件的常规操作。这一指针变量被称为文件指针。 文件指针的定义形式: FILE *文件指针变量名; 例如: FILE *myFile; /*定义了一个名为myFile的文件指针。*/

11 11.1 文件的基本概念 FILE指针 下面列出Turbo C系统对FILE类型的定义(该定义可从Turbo C的头文件stdio.h中找到):  typedef struct { short level; /* level表明文件缓冲区的状态是满还是空*/ unsigned flags; /* flags为文件状态标志符 */ char fd; /* fd为文件描述符*/ unsigned char hold; /* hold为没有文件缓冲区则不能获得字符 */ short bsize; /* bsize表明文件缓冲区的尺寸*/ unsigned char *buffer; /*指针buffer指向数据交换的缓冲区*/ unsigned char *curp; /*指针curp指向文件的当前活动指针*/ unsigned istemp; /* istemp表明文件是否是临时文件 */ short token; /* token用于文件合法性检查*/ } FILE; 因此,使用文件操作的程序,必须写上:#include “stdio.h”。

12 11.1 文件的基本概念 文件位置指针 C语言规定:每一个文件都必须设置一个位置指针(文件指针)来控制文件的访问位置,其规律如下。 ◆ 文件打开时指针自动指向文件的开始位置; ◆ 每读取一个单元内容文件位置指针自动顺序向后移动一定的偏移量(该偏移量的字节数由所读取单元的数据类型决定); ◆ 读到文件的结尾,则文件的位置指针指向一个特殊的位置——EOF。 ◆ 对文件进行顺序写操作时,数据写入到文件位置指针所指向的位置。写入后文件位置指针自动向后移动到一个新的位置,等待下一次的写入操作。 ◆ 可将文件位置指针移动到任何位置,实现对文件的随机读写访问。

13 11.1 文件的基本概念 文件结束符 文件指针移动到文件的最后一个字节时,C语言系统会返回文件的结束标识符EOF。EOF是一个系统常量,其值被定义为-1,是在头文件stdio.h中被定义的。 stdio.h中的定义如下: #define EOF (-1) /* End of file indicator */ 注意:EOF判断文件是否结束只适用于文本文件,而不适用于二进制文件;对于二进制文件,直接使用feof()函数判断文件是否结束,当函数feof()的返回值为1,则表明文件位置指针已经到达文件的结束位置,否则返回值为0,则表明文件还未结束。函数feof()的判断方法对于文本文件也是非常有效。

14 11.1 文件的基本概念 11.1.8 访问文件 访问文件主要操作过程如下:
访问文件 访问文件主要操作过程如下: ■打开文件(Open File):为文件准备相应的控制信息结构体与文件缓冲区,并在结构体与文件之间、缓冲区与文件之间建立起关联; ■读取文件操作(Read File):将外部存储介质中文件存储的信息读取出来放在计算机内存中; ■写入文件操作(Write File):将外界的信息存放到文件中去; ■关闭文件操作(Close File):将放于内存中的文件数据写回该文件,并释放文件占用的内存空间,切断文件与内存相应数据区域的关联。

15 11.1 文件的基本概念 访问文件 总之,文件文件操作必须是:“先打开,后读写,最后关闭”。如下图所示。

16 11.2 文件的打开与关闭 11.2.1 打开文件函数fopen()
打开文件使用fopen()函数实现。打开文件格式为: FILE *fp; fp= fopen(文件名,使用方式); 文件名:为包含访问路径的文件名字符串。 打开文件时,一但发生以下情况时,打开文件操作会失败,函数fopen()会返回一个不指向任何对象的NULL值。 ⑴文件所在的设备没有准备好; ⑵给定的路径上没有指定的文件; ⑶文件名拼写错误; ⑷试图以不正确的使用方式打开某个文件。 编程中经常检测函数fopen()是否返回NULL值来判断打开文件操作是否成功。

17 11.2 文件的打开与关闭 打开文件函数fopen() 文件的使用方式列表

18 11.2 文件的打开与关闭 11.2.1 打开文件函数fopen()
【例11.1】 下面的程序试着打开一个用于只读的文本文件,并检测打开是否成功。 #include <stdio.h> void main() { FILE *fp; fp=fopen("c:\Example\myFile.txt ","r"); if (fp==NULL) {printf("Failure to Open the Specified File!\n"); exit(0); } } 如果文件打开成功,fp就指向myFile.txt文件,否则fp的值为NULL。当文件打开失败,程序输出相应的错误信息提示,并退出系统。

19 11.2 文件的打开与关闭 11.2.2 关闭文件函数fclose() 文件操作结束前,必须关闭文件。
执行关闭文件操作时,系统会对文件缓冲区中的数据写入文件,并释放文件指针指向的存放文件信息结构体的内存资源。否则可能会引发数据的丢失。 关闭文件使用fclose()函数。格式如下: fclose(文件指针) ; 其中的“文件指针”参数,就是保存打开文件操作时fopen函数返回值的FILE指针变量。

20 11.3 文件的顺序读写 顺序读写文件:是指对文件的访问次序要按照数据在文件中的实际存放次序来进行,而不允许文件位置指针以跳跃的方式来读取数据或插入到任意位置写入数据。 根据文件顺序读写的信息规模,可将顺序读写文件的函数分为四类: ①    一次读写一个字符; ② 一次读写一个字符串; ③ 以格式化控制方式一次操作多个类型数据对象的读写函数; ④ 以数据块为操作对象的读写函数。 下面分专题对这四类函数进行介绍。

21 11.3 文件的顺序读写 字符读写函数 1. 读取文件中一个字符的函数fgetc() fgetc()函数实现从一个指定的文件中读取一个字符数据的功能。fgetc()函数的调用形式:c=fgetc(文件指针); 例如: FILE * fp; char c; c=fgetc(fp); fgetc()函数返回读取的字符。如果文件位置指针移到了文件结尾,则返回EOF(其值为-1)。 2. 写入一个字符到文件的函数fputc() fputc()函数实现将一个字符数据写入指定的文件中去的功能。fputc()函数调用方式为:FILE * fp; char c; fputc(c,fp); fputc()函数具有返回值,当向文件输出字符成功,则返回输出的字符,如果输出失败,则返回一个EOF。

22 11.3 文件的顺序读写 11.2.1 打开文件函数fopen()
【例11.2】 打开一个由键盘输入名字的文本文件,并为它写入一些用户输入的字符。 #include "stdio.h" #include "stdlib.h" void main() { FILE *fp; char ch,filename[10]; printf("Please input the file name:"); /*输出提示信息*/ scanf("%s",filename); /*输入要打开的文件名*/ if((fp=fopen(filename,"w"))==NULL) /*打开文件操作失败*/ {printf("cannot open file\n"); exit(0); } /*终止程序*/ ch=getchar(); /*接收在执行scanf语句时最后输入的回车符*/ printf("Please input data('#'to stop input):\n"); /*输出提示信息*/ ch=getchar(); /*接受第一个有效字符*/ while(ch!='#') {fputc(ch,fp); /*输出到文件*/ putchar(ch); /*将字符显示到屏幕*/ ch=getchar(); } putchar(10); /*向屏幕输出一个换行符*/ fclose(fp); /*关闭文件*/ getch(); }

23 11.3 文件的顺序读写 11.2.1 打开文件函数fopen()
程序的运行结果如下: 图11-5 例11-2的运行结果:   程序运行过程中用户与机器的交互(人机交互)信息为: file.c (输入磁盘文件名) computer and c# (输入一个字符串) computer and c (输出一个字符串) 本例在运行时,从键盘输入磁盘的文件名“file.c”,然后输入要写入文件的字符“coumpter and c#”,“#”是文件结束的标志。程序将“coumpter and c” 这些字符显示在屏幕上,同时还要将它们写入以“file.c”命名的磁盘文件中。 程序中的exit()是标准c的库函数,其功能为终止程序。

24 11.3 文件的顺序读写 字符串读写函数 1. 读取文件中读取一个字符串的函数fgets() fgets()函数实现从一个文件指针指定的文件中读取指定长度字符串的功能。fgets()函数的一般调用形式为: fgets(str, n,fp); 其中:参数fp为文件指针; 参数str为字符数组,用来存放文件中读取来的字符串; 参数n则指定要获取字符串的长度。实际上fgets()函数最多只能从文件中获取n-1个字符,但在读取字符串的最后位置的后面,系统将自动添加一个’\0’字符。 如果函数在读取n-1个字符之前碰到了换行符’\n’或文件结束符EOF,则系统会中止读入,并将遇到的换行符也作为有效的读入字符。 fgets()函数在执行成功以后,会将字符数组str的地址作为返回值,如果读取数据失败或一开始读就遇到了文件结束符,则返回一个NULL值。

25 11.3 文件的顺序读写 字符串读写函数 2. 写入一个字符串到文件的函数fputs() fputs()函数实现将一个字符串写入到指定的文件中去的功能。fputs()函数的一般调用形式为: fputs(str,fp); fputs()函数具有整型的返回值,当向文件输出字符串操作成功时,则返回0值,如果输出失败,则返回一个EOF(-1)。 注意:fputs()函数并不将字符串str尾部的结束符“\0”写入文件。字符串在文件中作为独立的一行,需要用fputs(“\n”,fp)语句为这一字符串添加一个换行符;否则连续输出的多个字符串成为一个整体,这样在今后的读取数据时就无法将这些字符串有效的区分开来。

26 11.3 文件的顺序读写 字符串读写函数 【例11.3】 用字符串读函数实现对文本文件内容的读取,并将行号和每行的数据显示到屏幕上。文件名采用键盘上输入的方式提供。 #include "stdio.h" void main() { char buffer[256],fname[20]; /*定义数据缓冲区与文件名变量*/ FILE *fp; int lineNum =1; /*定义用于显示行号的变量lineNum*/ printf("Please input the file-name:"); scanf("%s",fname); /*输入要读取文件的名称*/ if((fp=fopen(fname,“r”))==NULL) /*文件打开失败*/ {printf(“Can not open the %s file!\n ”,fname); return; } /*调用fgets()函数读取文件数据并显示*/ while(fgets(buffer,256,fp)!=NULL) { printf(“%3d:%s”, lineNum,buffer); /*显示行号与一行数据*/ if(lineNum%20==0) /*显示超过20行时暂停*/ { printf("continue"); getchar (); } lineNum++; } /*行号变量自增*/ fclose(fp); } /*关闭文件*/

27 11.3 文件的顺序读写 字符串读写函数 在运行程序前,需要准备一个有多行数据的文本文件,用于程序的显示。 程序的运行结果如下:  

28 11.3 文件的顺序读写 格式化读写函数 1.格式化输入函数fscanf() fscanf ()函数实现从指定的文件中将一系列指定格式的数据读取出来的功能。 fscanf ()函数的原型定义为: int fscanf(FILE * fp,char * format[,argument1,argument2,……argumentm]); 即:int fscanf(文件指针,格式字符串,输入表列); 一般调用形式为:fscanf(fp,format,&argument1,&argument2,……,&argumentm]); fscanf ()函数从文件指针fp指向的文件中,按照format规定的格式,将m(m>=1)个数据读取出来,并分别放入到对应的m个变量argumentk(1<=k<=m)中。 例如:下列程序从fp指向的文件中,将文件位置指针开始处的三个数据分别读入到字符串变量name,整形变量age和实型变量salary内。 char name[8]; int age; float salary; fprintf(fp,”%s,%d,%f”,name,&age,&salary);

29 11.3 文件的顺序读写 格式化读写函数 2.格式化输出函数fprintf () fprintf ()函数实现将一系列格式化的数据写入指定的文件中去的功能。fprintf()函数的原型定义为: int fprintf (FILE * fp,char * format[,argument1,argument2,……argumentm]); 即:int fprintf(文件指针,格式字符串,输出表列); 一般调用形式为:fprintf(文件指针,格式字符串,输出表列); fprintf ()函数将m(m>=1)个变量argument1、argument2、……argumentm,按照format规定的格式,写入到文件指针fp指向的文件中。 例如:下列程序将一个人的信息:字符串变量name的值,整形变量age的值和实型变量salary的值,分别按%s,%d和%8.2f的格式输出到fp指向的文件中。 char name[ ]=”Jack”; int age=26; float salary= ;

30 11.3 文件的顺序读写 格式化读写函数 注意: ①用fprintf()函数和fscanf()函数对磁盘进行读写非常方便,但是,由于在输入时要将数据的ASCⅡ值转换成二进制的形式,输出时又需要再将二进制形式转换成字符形式,这需要花费一定的时间。因此在内存与磁盘频繁交换数据的情况下,最好不用fprintf()函数和fscanf()函数,改用fread()函数和fwrite()函数。 ②用fscanf()函数从文件中进行格式化输入时,要保证格式字符串所控制的数据格式与文件中的数据类型保持一致,否则将会出错。

31 11.3 文件的顺序读写 格式化读写函数 【例11.4】 从键盘上输入一个字符串和一个十进制整数,将它们写入到当前目录下的磁盘文件test.dat中,然后再从test.dat文件中读出并显示到屏幕上。 #include <stdio.h> main( ) { char s[80]; int a; FILE *fp; if ((fp=fopen("test.dat", "w")) == NULL) /* 以写方式打开文本文件 */ { printf ("Cannot open this file!\n"); exit(1); } scanf ("%s%d", s, &a); /* 从键盘上读取两个数据 */ fprintf(fp, "%s %d", s, a); /* 以格式输出方式将数据写入文件 */ fclose (fp); if ((fp=fopen("test", "r")) == NULL) /* 以读方式打开文本文件 */ {printf ("Cannot open file!\n"); exit(1); } fscanf (fp, "%s%d", s, &a); /* 从文件中读取两个数据 */ printf("%s %d\n", s, a); /* 将数据显示到标准输出设备(屏幕)上 */ fclose(fp); }

32 11.3 文件的顺序读写 数据块读写函数 1. 读取文件中一组数据的函数fread() fread()函数实现从文件指针指定的文件中读取指定长度数据块的功能。fread()函数的原型定义为: int fread(char * buffer,int size,int count,FILE * fp); 其中参数buffer为指向为存放读入数据设置的缓冲区的指针或作为缓冲区的字符数组; 参数size为读取的数据块中每个数据项的长度(单位为字节); 参数count为要读取的数据项的个数;fp是文件型指针。 如果执行fread()函数时没有遇到了文件结束符,则实际读取的数据长度应为:size×count(字节)。 fread()函数在执行成功以后,会将实际读取到的数据项个数作为返回值;如果读取数据失败或一开始读就遇到了文件结束符,则返回一个NULL值。

33 11.3 文件的顺序读写 数据块读写函数 2. 写入一组数据到文件的函数fwrite() fwrite()函数实现将一个字符串写入到指定的文件中去的功能。fputs()函数的原型定义为: int fwrite(char * buffer,int size,int count,FILE * fp); 其中参数buffer是一个指针,它指向输出数据缓冲区的首地址; 参数size为待写入文件的数据块中每个数据项的长度(单位为字节); 参数count为待写入文件的数据项的个数;fp是文件型指针。 fwrite()函数具有整型的返回值,当向文件输出操作成功时,则返回写入的数据块的个数,如果输出失败,则返回NULL。 注意:利用fread()函数和fwrite()函数读写二进制文件时非常方便,可以对任何类型的数据进行读写。当fread()和fwrite()调用成功时,函数都将返回count的值,即输入输出数据项的个数。

34 11.3 文件的顺序读写 数据块读写函数 【例11.5】 利用键盘输入四个学生的基本信息,然后将这些信息保存到当前目录下的磁盘文件“stu_info.dat”中。  #include “stdio.h” #define SIZE 4 struct student_type /*将学生基本信息的数据结构定义为一个结构体*/ { char name [10]; int num; int age; char addr[15]; } stud[SIZE]; /*定义学生基本信息结构体对象数组存放四个学生的信息*/

35 11.3 文件的顺序读写 数据块读写函数 void save() { FILE *fp; int i; if((fp=fopen("stu_info.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); /*关闭文件*/ }

36 11.3 文件的顺序读写 数据块读写函数 /*主函数,实现从键盘输入四个学生的信息数据*/ 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(); /*调用函数save(),将输入的数据保存到磁盘文件中*/ } 上述程序仅仅实现了数据写入文件的过程。下面编写程序,读取例11-5生成的数据文件中的每位学生的信息记录,并显示到屏幕上。

37 11.3 文件的顺序读写 数据块读写函数 【例11.6】读取当前目录下的磁盘文件“stu_info.dat”中的学生信息记录,并将它们显示到输出终端上来。 #include "stdio.h" #define SIZE 4 struct student_type { char name[10]; int num; int age; char addr[15]; } stud[SIZE];

38 11.3 文件的顺序读写 数据块读写函数 /*主函数,实现从文件中读取四个学生的信息数据并显示到屏幕上*/ void main() { int i; FILE *fp; fp=fopen("stu_info.dat ","rb"); /**/ 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); /*关闭文件*/ }

39 11.3 文件的顺序读写 数据块读写函数 图11-7 例11-6的运行结果 不难看出,输出的内容正是例11-5中写入文件的内容。

40 11.4 文件的随机读写 前面介绍了对文件的顺序读写操作,这些操作都是从文件的第一个有效数据(或某个位置)开始的,依照数据在文件存储设备中的先后次序进行读写,在读写过程中,文件位置指针自动移动。但在实际应用中,往往需要对文件中某个特定位置处的数据进行处理,换言之,就是读完一个字节的内容后,并不一定要读写其后续的字节数据,可能会强制性地将文件位置指针移动到用户所希望的特定位置,读取该位置上的数据,这就是随机读写文件。 C语言提供了对文件的随机读写功能。在随机方式下,系统并不按数据在文件中的物理顺序进行读写,而是可以读取文件任何有效位置上的数据,也可以将数据写入到任意有效的位置。

41 11.4 文件的随机读写 C语言通过提供文件定位函数来实现随机读写功能。 获取文件位置指针当前值的函数ftell() ftell()函数的功能是获得并返回文件位置指针的当前值。ftell()函数的原型定义为: long ftell(FILE * fp); 其中参数fp是文件型指针,指向当前操作的文件。 rewind()函数的返回值为文件位置指针的当前位置。如果rewind()函数执行时出现错误,则返回长整型的-1(即-1L)。

42 11.4 文件的随机读写 2. 重置文件位置指针的函数rewind() rewind()函数的功能是使文件的位置指针移到文件的开头处。rewind()函数的原型定义为: void rewind(FILE * fp); 其中参数fp是文件型指针,指向当前操作的文件。 rewind()函数没有返回值,其作用在于:如果要对文件进行多次读写操作,可以在不关闭文件的情况下,将文件位置指针重新设置到文件开头,从而能够重新读写此文件。如果没有rewind()函数,每次重新操作文件之前,需要将该文件关闭后再重新打开,这种方式不仅效率低下,而且操作也不方便。使用rewind()函数便能克服这一缺陷。

43 11.4 文件的随机读写 【例11.7】 有一个文本文件file1.dat,两次读写它的内容,第一次将它的内容显示在屏幕上,第二次将它的内容复制到另一个文件fiel2.dat上。以下为实现该功能的程序代码。  #include "stdio.h" void main() { FILE *fp1,*fp2; fp1=fopen("file1.dat","r"); fp2=fopen("fiel2.dat","w"); while(!feof(fp1)) putchar(getc(fp1)); rewind(fp1); while(!feof(fp1)) putc(getc(fp1),fp2); fclose(fp1); fclose(fp2); }

44 11.4 文件的随机读写 3. 移动文件位置指针的函数fseek() 函数fseek()可以实现改变文件位置指针到指定位置的操作。fseek()函数的原型定义为: int fseek(FILE * fp,long offset,int origin); 即:int fseek(文件类型指针,位移量,起始点); 其中fp为打开的文件指针,参数offset为文件位置指针移动的位移量(单位为字节),参数origin指示出文件位置指针移动的起始点(或称基点)位置。当执行fseek()函数后,文件位置指针新的位置是以起始点为基准,向后(offset为正值)/或向前(offset为负值)移动offset个字节。文件位置指针的新位置可以用公式“origin+offset”来计算得出。

45 11.4 文件的随机读写 二进制文件的基点origin 可以取以下三个常量值之一: ⑴SEEK_SET(也可直接用数字0表示):此时文件位置指针从文件的开始位置进行移动; ⑵SEEK_CUP(对应值为1): 此时文件位置指针从文件的当前位置进行移动; ⑶SEEK_END(对应值为2): 此时文件位置指针从文件的结束位置进行移动。 文本文件的基点origin只能取SEEK_SET常量值(或取0值),而origin的值应为0。 fseek()函数常用于二进制文件中,对于文本文件则不常使用,因为文本文件要进行字符的转换,这会为文件位置指针的计算带来混乱。fseek()函数的调用形式为: fseek()函数返回一个整形值。如果函数执行成功,返回0值;否则,返回一个非0值。 下面给出fseek()函数调用的两个例子: ①fseek(fp,50L,1),将fp指向的文件的位置指针向后移动到离当前位置50个字节处; ②fseek(fp,-100L,2),将fp指向的文件的位置指针从文件末尾处向前回退100个字节。

46 11.4 文件的随机读写 【例11.8】 在当前目录下有一二进制文件information.dat,文件中存储有学生信息数据。编程实现按指定位置读取该文件中的数据,显示到屏幕上,并统计文件的总字节数目,也显示到屏幕上。 以下为实现该功能的程序代码。  #include "stdio.h" struct student { char name[20];int num; }; /*主函数*/ main() { int i=0; long n=0; FILE *fp=NULL; struct student a = {0}; fp = fopen("information.dat","rb"); if(fp==NULL) { printf("Can't open!\n"); exit(0); } printf("Record in file information.dat:\n");

47 11.4 文件的随机读写 for(i=1;i<5;i+=2) { fseek(fp,i*sizeof(struct student),SEEK_SET); /*定位文件位置指针*/ n=ftell(fp); /*获取文件位置指针当前值*/ fread(&a,sizeof(struct student),1,fp); /*读取数据块*/ printf(“current:%ldth byte,%dth record:%s %d\n”,n,i+1,a.name,a.num); fseek(fp,-3l*sizeof(struct student),2); /*重新定位文件位置指针*/ n=ftell(fp); /*重新读取数据块*/ fread(&a,sizeof(struct student),1,fp); printf(“current:%ldth btype,record is:%s %d\n”,n,a.name,a.num); rewind(fp); /*重置文件位置指针到文件开始*/ n=ftell(fp); /*获取文件位置指针当前值*/ fread(&a,sizeof(struct student),1,fp); printf(“current:%ldth btype,frist record :%s %d\n”,n,a.name,a.num); fseek(fp,-0l*sizeof(struct student),2); /*重新定位文件位置指针到文件尾部*/ n=ftell(fp); /*计算文件总字节数目*/ printf(“total bytes:%ld\n”,n); /*显示文件总字节数目*/ fclose(fp); } getch(); }

48 11.4 文件的随机读写 【例11.8】 在当前目录下有一二进制文件information.dat,文件中存储有学生信息数据。编程实现按指定位置读取该文件中的数据,显示到屏幕上,并统计文件的总字节数目,也显示到屏幕上。 以下为实现该功能的程序代码。  #include "stdio.h" struct student { char name[20];int num; }; /*主函数*/ main() { int i=0; long n=0; FILE *fp=NULL; struct student a = {0}; fp = fopen("information.dat","rb"); if(fp==NULL) { printf("Can't open!\n"); exit(0); } printf("Record in file information.dat:\n"); for(i=1;i<5;i+=2) { fseek(fp,i*sizeof(struct student),SEEK_SET); /*定位文件位置指针*/ n=ftell(fp); /*获取文件位置指针当前值*/ fread(&a,sizeof(struct student),1,fp); /*读取数据块*/ printf("current:%ldth byte,%dth record:%s %d\n",n,i+1,a.name,a.num); fseek(fp,-3l*sizeof(struct student),2); /*重新定位文件位置指针*/ n=ftell(fp); /*重新读取数据块*/ fread(&a,sizeof(struct student),1,fp); printf("current:%ldth btype,record is:%s %d\n",n,a.name,a.num); rewind(fp); /*重置文件位置指针到文件开始*/ n=ftell(fp); /*获取文件位置指针当前值*/ fread(&a,sizeof(struct student),1,fp); printf("current:%ldth btype,frist record :%s %d\n",n,a.name,a.num); fseek(fp,-0l*sizeof(struct student),2); /*重新定位文件位置指针到文件尾部*/ n=ftell(fp); /*计算文件总字节数目*/ printf("total bytes:%ld\n",n); /*显示文件总字节数目*/ fclose(fp); } getch(); }

49 11.5 文件检测 在对文件的访问过程中,经常会因各种原因,产生读写数据的错误。如同人们在做数学题时,要进行错误检查一样,程序中也应该为文件处理加上一些必要的错误检测手段,这样就能够在程序运行期间检测到一些错误,以便进行必要的错误处理,增强程序的健壮性。此外,有时还需要对文件的一些特殊的状态进行检测,以便决定进行相应的处理,从而增强程序的灵活性。 C语言系统专门提供了一些用于检测文件特殊状态与读写错误的函数。下面简单地介绍一下这些函数的功能与用法。 文件结束检测函数feof() 调用格式为:feof(文件指针); 它的功能是:判断文件位置指针当前是否处于文件结束位置。当处于文件结束位置时,返回1值,否则返回非零值。

50 11.5 文件检测 2.读写文件出错检测函数ferror() 调用格式为:ferror(文件指针); 它的功能是:检查文件在使用输入输出函数(如putc,getc,fread,fwrite等)进行读写时,是否有错误发生。如果没有错误产生则返回非零值,否则返回1。 特别要注意的是:对于同一个文件,每次执行对文件的读写语句,然后马上调用函数ferror均能得到一个相应的返回值,由该值可以判断出上一次读写数据是否正常。因此在调用一个输入输出函数后,应当立即对ferror的返回值进行检查,否则在下次读写数据时,函数ferror的值会丢失。 在执行fopen函数时,ferror函数的初始值将被自动置为0。 我们经常用下面的这种方式来调用ferror函数: if (ferror(fp)) { printf(“Operation of File is Error!\n”); fclose(fp); exit(0); }

51 11.5 文件检测 3.将文件出错标志和文件结束标志置0的函数clearerr() 调用格式为:clearerr(文件指针); 它的功能是:用于清除出错标志和文件结束标志,将这些标志置为0。 clearerr的作用是使文件错误的标志和文件结束标志置为0。假设在调用一个输入输出函数时出现了错误,ferror函数会返回一个非零值,此时如果调用clearerr(fp) 函数,ferror(fp) 的值将会被自动置0。 只要出现错误标志,ferror(fp)函数的状态将会一直保留不变,这种状态会一直保持到对同一文件调用clearerr函数,或者使用rewind函数,或者调用其他任意输入输出函数。

52 11.6 程序综合举例 1.在C盘根目录下有一名为source.dat的顺序文本文件,其中存放着60个整数数据。顺序读出source.dat文件中的60个整数数据,将它们平均分为三组(每组有20个整数)。假设分出的三个数据组按先后次序分别称为A组、B组与C组,试编程实现对A、B、C三个数据组进行以下处理的功能: (1)A组与C组位置对换,但每个组的数据对换后保持原有排列顺序不变; (2)对B组数据的排列顺序进行逆/反转,但组在文件中的整体位置保持不变; (3)将处理后的三组数据写入到另一个名为“destination.dat”的顺序文本文件中,并存储到C盘根目录下。

53 11.6 程序综合举例 下面用一个假定的实例进一步说明题意: 假定读出的source.dat文件中的60个整数数据如下表所示:

54 11.6 程序综合举例 解题分析: ①首先要读取文件source.dat中的数据到内存中已设定好的数据结构中(此处采用数组); ②编写算法,完成A组与C组数据的位置对换功能; ③编写算法,完成B组数据的逆转运算功能; ④至此为止,已在内存中完成A组与C组位置的对换功能与B组数据的逆转功能,还需将处理后的内存数据结果存入文件destination.dat中; ⑤最后要将文件source.dat与destination.dat关闭掉。

55 11.6 程序综合举例 /* 主程序功能:通过调用函数,完成读取文件source.dat到数组X中,*/ /*然后对X进行处理,将处理后的结果存入文件destination.dat中 */ void main() { FILE *sf,*df; int x[60],i; if ((sf=fopen("c:\\source.dat","r"))==NULL) { printf("File open fail!\n"); exit(0); } for (i=0;i<60;i++) fscanf(sf,"%d",(x+i)); process(x); fclose(sf);   if ((df=fopen("c:\\destination.dat","w"))==NULL) { printf("File open fail!\n"); exit(0); } for (i=0;i<60;i++) fprintf(df,"%d\n",x[i]); fclose(df); }

56 11.6 程序综合举例 2.为比较源文件source.dat与目标文件destination.dat的内容,以便检测这两个文件是否符合前面的操作要求,需要编写另一个程序,用来对照显示两个数据文件的内容。 下面给出已经调试通过的参考程序(程序文件名为application_2.c)。  #include<stdio.h> /* getData()函数读取文件fname的数据并存入data数组中 */ void getData(char fname[],int data[]) { FILE *fp; int k; if ((fp=fopen(fname,"r"))==NULL) { printf("File open fail!\n"); exit(0); } for (k=0;k<60;k++) fscanf(fp,"%d",(data+k)); fclose(fp); }

57 11.6 程序综合举例 /* dispData函数将data数组中的元素以每行十个的形式显示出来 */ void dispData(int data[]) { int k; for (k=0;k<60;k++) { if (k%10==0) printf("\n"); printf("%-6d|",data[k]); } }

58 11.6 程序综合举例 /* 主程序完成读文件source.dat、destination.dat并显示数据的功能 */ void main() { int sdata[60]; int ddata[60]; getData("c:\\source.dat",sdata); getData("c:\\destination.dat",ddata); printf("\nThe data of Source file:\n"); dispData(sdata); printf("\n\nThe data of Distination file:"); dispData(ddata); getch(); }

59 11.6 程序综合举例 第二个程序application_2.c运行后的效果如下图所示。 上图文件source.dat与destination.dat的数据对照

60 11.7 上机实训 实训目的和要求 ⑴掌握文件和文件指针的概念以及文件的定义方法; ⑵了解文件打开和关闭的概念以及方法; ⑶掌握有关文件的函数。 实训内容和步骤 ⑴从键盘输入一行字符串,然后将其一文件的形式存到磁盘上。文件的名为file.dat; ⑵⑸从磁盘文件file1.dat读如一行字符,见其中所有小写字母改为大写字母,然后输入到磁盘文件file2.dat中; ⑶对上面已经存在的两个文件,编程序从这两个文件中读出各行字符,逐个比较这两个文件中相应的行和列上的字符,如果遇到互不相同的字符,输出它是第几行第几列的字符; ⑷利用所学的文件知识试编程序,统计一篇文章中的大写字母的个数。


Download ppt "11.1 文件的基本概念 11.2 文件的打开与关闭 11.3 文件的顺序读写 11.4 文件的随机读写 11.5 文件检测"

Similar presentations


Ads by Google