1、C C语言程序设计语言程序设计姚望舒姚望舒计算机科学与技术学院计算机科学与技术学院苏州大学苏州大学10.1 文件的有关基本知识文件的有关基本知识10.2 打开与关闭文件打开与关闭文件10.3 顺序读写数据文件顺序读写数据文件10.4 随机读写数据文件随机读写数据文件10.5 文件读写的出错检测文件读写的出错检测10.1.1 什么是文件什么是文件10.1.2 文件名文件名10.1.3 文件的分类文件的分类10.1.4 文件缓冲区文件缓冲区10.1.5 文件类型指针文件类型指针输入输出是数据传送的过程,数据如流水一输入输出是数据传送的过程,数据如流水一样从一处流向另一处,因此常将输入输出形样从一处
2、流向另一处,因此常将输入输出形象地称为流象地称为流(stream),即数据流。流表示,即数据流。流表示了信息从源到目的端的流动。了信息从源到目的端的流动。输入操作时,数据从文件流向计算机内存输入操作时,数据从文件流向计算机内存输出操作时,数据从计算机流向文件输出操作时,数据从计算机流向文件“流流”是一个传输通道,数据可以从运行环是一个传输通道,数据可以从运行环境流入程序中,或从程序流至运行环境境流入程序中,或从程序流至运行环境从从C程序的观点来看,无论程序一次读写程序的观点来看,无论程序一次读写一个字符,或一行文字,或一个指定的数一个字符,或一行文字,或一个指定的数据区,作为输入输出的各种文件
3、或设备都据区,作为输入输出的各种文件或设备都是统一以是统一以逻辑数据流逻辑数据流的方式出现的。语的方式出现的。语言把文件看作是一个字符(或字节)的序言把文件看作是一个字符(或字节)的序列。列。一个输入输出流就是一个字符流或字一个输入输出流就是一个字符流或字节节(内容为二进制数据内容为二进制数据)流流。的数据文件由一连串的字符(或字节)的数据文件由一连串的字符(或字节)组成,而不考虑行的界限,两行数据间不组成,而不考虑行的界限,两行数据间不会自动加分隔符,对文件的存取是以字符会自动加分隔符,对文件的存取是以字符(字节)为单位的。输入输出数据流的开(字节)为单位的。输入输出数据流的开始和结束仅受程
4、序控制而不受物理符号(始和结束仅受程序控制而不受物理符号(如回车换行符)控制,这就增加了处理的如回车换行符)控制,这就增加了处理的灵活性。这种文件称为灵活性。这种文件称为流式文件流式文件。文件要有一个唯一的文件标识,以便用户文件要有一个唯一的文件标识,以便用户识别和引用。识别和引用。文件标识包括三部分:文件标识包括三部分:(1)文件路径文件路径(2)文件名主干文件名主干(3)文件后缀文件后缀文件路径表示文件在外部存储设备中的位文件路径表示文件在外部存储设备中的位置。如:置。如:D:CCtempfile1.datu表示表示file1.dat文件存放在文件存放在D盘中的盘中的CC目录下目录下的的t
5、emp子目录下面子目录下面文件路径文件路径文件名主干文件名主干文件后缀文件后缀文件路径表示文件在外部存储设备中的位文件路径表示文件在外部存储设备中的位置。如:置。如:D:CCtempfile1.datu表示表示file1.dat文件存放在文件存放在D盘中的盘中的CC目录下目录下的的temp子目录下面子目录下面文件名文件名文件路径表示文件在外部存储设备中的位文件路径表示文件在外部存储设备中的位置。如:置。如:D:CCtempfile1.datu表示表示file1.dat文件存放在文件存放在D盘中的盘中的CC目录下目录下的的temp子目录下面子目录下面命名规则遵循标命名规则遵循标识符的命名规则识符
6、的命名规则文件路径表示文件在外部存储设备中的位文件路径表示文件在外部存储设备中的位置。如:置。如:D:CCtempfile1.datu表示表示file1.dat文件存放在文件存放在D盘中的盘中的CC目录下目录下的的temp子目录下面子目录下面一般不超过一般不超过3个字母(个字母(doc、txt、dat、c、cpp、obj、exe、ppt、bmp等)等)根据数据的组织形式,数据文件可分为根据数据的组织形式,数据文件可分为ASCII文件文件和和二进制文件二进制文件。u数据在内存中是以二进制形式存储的,如果不数据在内存中是以二进制形式存储的,如果不加转换地输出到外存,就是加转换地输出到外存,就是二进
7、制文件二进制文件u如果要求在外存上以如果要求在外存上以ASCII代码形式存储,代码形式存储,则需要在存储前进行转换则需要在存储前进行转换uASCII文件又称文本文件,每一个字节放一文件又称文本文件,每一个字节放一个字符的个字符的ASCII代码代码字符一律以字符一律以ASCII形式存储形式存储数值型数据既可以用数值型数据既可以用ASCII形式存储,也形式存储,也可以用二进制形式存储可以用二进制形式存储u如有整数如有整数10000,如果用,如果用ASCII码形式输出码形式输出到磁盘,则在磁盘中占个字节到磁盘,则在磁盘中占个字节(每一个字符每一个字符占一个字节占一个字节),而用二进制形式输出,则在磁
8、,而用二进制形式输出,则在磁盘上只占盘上只占4个字节个字节(用用VC+C时时)(1)(0)(0)(0)(0)ASCII形式形式二进制形式二进制形式(10000)ANSI C标准采用标准采用“缓冲文件系统缓冲文件系统”处理处理数据文件数据文件所谓所谓缓冲文件系统缓冲文件系统是指系统自动地在内存是指系统自动地在内存区为程序中每一个正在使用的文件开辟一区为程序中每一个正在使用的文件开辟一个文件缓冲区个文件缓冲区从内存向磁盘输出数据必须先送到内存中从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘的缓冲区,装满缓冲区后才一起送到磁盘去去如果从磁盘向计算机读入数据,则一次从如果从磁
9、盘向计算机读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区(磁盘文件将一批数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(给程序变量)数据送到程序数据区(给程序变量)程序数据区程序数据区输出文件缓冲区输出文件缓冲区输入文件缓冲区输入文件缓冲区磁盘磁盘从内存向磁盘输出数据从内存向磁盘输出数据装满缓冲区装满缓冲区程序数据区程序数据区输出文件缓冲区输出文件缓冲区输入文件缓冲区输入文件缓冲区磁盘磁盘从磁盘向计算机读入数据从磁盘向计算机读入数据充满缓冲区充满缓冲区缓冲文件系统中,关键的概念是缓冲文件系统中,关键的概念是“文件类文件类型
10、指针型指针”,简称,简称“文件指针文件指针”u每个被使用的文件都在内存中开辟一个相应的每个被使用的文件都在内存中开辟一个相应的文件信息区,用来存放文件的有关信息(如文文件信息区,用来存放文件的有关信息(如文件的名字、文件状态及文件当前位置等)件的名字、文件状态及文件当前位置等)u这些信息是保存在一个结构体变量中的。该结这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名为构体类型是由系统声明的,取名为FILE声明声明FILE结构体类型的信息包含在头文件结构体类型的信息包含在头文件“stdio.h”中中一般设置一个指向一般设置一个指向FILE类型变量的指针变类型变量的指针变量,然
11、后通过它来引用这些量,然后通过它来引用这些FILE类型变量类型变量FILE*fp1,*fp2,*fp3;文件文件f1的的文件信息区文件信息区fp1文件文件f2的的文件信息区文件信息区fp2文件文件f3的的文件信息区文件信息区fp310.2.1 用用fopen函数打开数据文件函数打开数据文件10.2.2 用用fclose函数关闭数据文件函数关闭数据文件对文件读写之前应该对文件读写之前应该“打开打开”该文件,在该文件,在使用结束之后应使用结束之后应“关闭关闭”该文件。该文件。所谓所谓“打开打开”是指为文件建立相应的信息是指为文件建立相应的信息区区(用来存放有关文件的信息用来存放有关文件的信息)和文
12、件缓冲和文件缓冲区区(用来暂时存放输入输出的数据用来暂时存放输入输出的数据)。在编写程序时,在打开文件的同时,一般在编写程序时,在打开文件的同时,一般都指定一个指针变量指向该文件,也就是都指定一个指针变量指向该文件,也就是建立起指针变量与文件之间的联系,这样建立起指针变量与文件之间的联系,这样就可以通过该指针变量对文件进行读写就可以通过该指针变量对文件进行读写所谓所谓“关闭关闭”是指撤销文件信息区和文件是指撤销文件信息区和文件缓冲区缓冲区 fopen函数的调用方式为:函数的调用方式为:FILE*fopen(文件名文件名,使用文件方式使用文件方式);例如:例如:fopen(“a1”,”r”);u
13、表示要打开名为表示要打开名为“a1”的文件,使用文件方的文件,使用文件方式为式为“读入读入”ufopen函数的返回值是指向函数的返回值是指向a1文件的指针文件的指针通常将通常将fopen函数的返回值赋给一个指向函数的返回值赋给一个指向文件的指针变量。如:文件的指针变量。如:FILE*fp;fp=fopen(“a1”,”r”);ufp和文件和文件a1相联系,相联系,fp指向了指向了a1文件文件ua1:有两种形式有两种形式l文件名:表示文件在工程路径文件名:表示文件在工程路径l绝对路径:绝对路径绝对路径:绝对路径+文件名文件名在打开一个文件时,通知编译系统以下在打开一个文件时,通知编译系统以下3个
14、信息:个信息:需要访问的文件的名字需要访问的文件的名字使用文件的方式(使用文件的方式(“读读”还是还是“写写”等)等)让哪一个指针变量指向被打开的文件让哪一个指针变量指向被打开的文件使用文件方式参见教材表使用文件方式参见教材表10.1。说明:说明:(1)用用“r”方式打开的文件只能用于向计算方式打开的文件只能用于向计算机输入而不能用作向该文件输出数据,而且机输入而不能用作向该文件输出数据,而且该文件应该已经存在,并存有数据,这样程该文件应该已经存在,并存有数据,这样程序才能从文件中读数据。序才能从文件中读数据。u不能用不能用“r”方式打开一个并不存在的文件,方式打开一个并不存在的文件,否则出错
15、。否则出错。说明:说明:(2)用用“w”方式打开的文件只能用于向该文方式打开的文件只能用于向该文件写数据(即输出文件),而不能用来向计件写数据(即输出文件),而不能用来向计算机输入。算机输入。u如果原来不存在该文件,则在打开文件前新如果原来不存在该文件,则在打开文件前新建立一个以指定的名字命名的文件。建立一个以指定的名字命名的文件。u如果原来已存在一个以该文件名命名的文件如果原来已存在一个以该文件名命名的文件,则在打开文件前先将该文件删去,然后重,则在打开文件前先将该文件删去,然后重新建立一个新文件。新建立一个新文件。说明:说明:(3)如果希望向文件末尾添加新的数据(不希如果希望向文件末尾添加
16、新的数据(不希望删除原有数据),则应该用望删除原有数据),则应该用“a”方式打开方式打开u但此时应保证该文件已存在;否则将得到出但此时应保证该文件已存在;否则将得到出错信息。错信息。u打开文件时,文件读写标记移到文件末尾打开文件时,文件读写标记移到文件末尾说明:说明:(4)用用r+、w+、a+方式打开的文件既可以方式打开的文件既可以用来输入数据,也可以用来输出数据。用来输入数据,也可以用来输出数据。u用用r+方式时该文件应该已经存在。方式时该文件应该已经存在。u用用w+方式则新建立一个文件,先向此文件方式则新建立一个文件,先向此文件写数据,然后可以读此文件中的数据。写数据,然后可以读此文件中的
17、数据。u用用a+方式打开的文件,原来的文件不被删去方式打开的文件,原来的文件不被删去,文件读写位置标记移到文件末尾,可以添,文件读写位置标记移到文件末尾,可以添加,也可以读。加,也可以读。说明:说明:(5)如果打开失败,如果打开失败,fopen函数将会带回一个函数将会带回一个出错信息。出错信息。fopen函数将带回一个空指针值函数将带回一个空指针值NULL常用下面的方法打开一个文件:常用下面的方法打开一个文件:if(fp=fopen(“file1”,r)=NULL)printf(“cannot open this filen”);exit(0);终止正在执行的程序终止正在执行的程序说明:说明:
18、(6)C标准建议用表标准建议用表10.1列出的文件使用方式列出的文件使用方式打开文本文件或二进制文件,但目前使用的打开文本文件或二进制文件,但目前使用的有些有些C编译系统可能不完全提供所有这些功能编译系统可能不完全提供所有这些功能说明:说明:(7)计算机输从计算机输从ASCII文件读入字符时,遇到文件读入字符时,遇到回车换行符,系统把它转换为一个换行符,回车换行符,系统把它转换为一个换行符,在输出时把换行符转换成为回车和换行两个在输出时把换行符转换成为回车和换行两个字符。在用二进制文件时,不进行这种转换字符。在用二进制文件时,不进行这种转换,在内存中的数据形式与输出到外部文件中,在内存中的数据
19、形式与输出到外部文件中的数据形式完全一致,一一对应。的数据形式完全一致,一一对应。说明:说明:(8)程序中可以使用程序中可以使用3个标准的流文件:标准输个标准的流文件:标准输入流、标准输出流、标准出错输出流。入流、标准输出流、标准出错输出流。u系统已对这系统已对这3个文件指定了与终端的对应关系个文件指定了与终端的对应关系u标准输入流是从终端的输入标准输入流是从终端的输入u标准输出流是向终端的输出标准输出流是向终端的输出u标准出错输出流是当程序出错时将出错信息发标准出错输出流是当程序出错时将出错信息发送到终端送到终端程序开始运行时系统自动打开这程序开始运行时系统自动打开这3个标准个标准流文件。因
20、此,程序编写者不需要在程流文件。因此,程序编写者不需要在程序中用序中用fopen函数打开它们。所以以前函数打开它们。所以以前我们用到的从终端输入或输出到终端都我们用到的从终端输入或输出到终端都不需要打开终端文件。不需要打开终端文件。关闭文件用关闭文件用fclose函数。函数。fclose函数调函数调用的一般形式为用的一般形式为fclose(文件指针文件指针);例如:例如:fclose (fp);如果不关闭文件将会如果不关闭文件将会丢失丢失数据数据。在顺序写时,先写入的数据存放在文件中在顺序写时,先写入的数据存放在文件中前面,后写入的数据存放在文件中后面前面,后写入的数据存放在文件中后面在顺序读
21、时,先读文件中前面的数据,后在顺序读时,先读文件中前面的数据,后读文件中后面的数据读文件中后面的数据对顺序读写来说,对文件读写数据的顺序对顺序读写来说,对文件读写数据的顺序和数据在文件中的物理顺序是一致的和数据在文件中的物理顺序是一致的 顺序读写需要用库函数实现顺序读写需要用库函数实现10.3.1 怎样向文件读写字符怎样向文件读写字符10.3.2 怎样向文件读写一个字符串怎样向文件读写一个字符串10.3.3 用格式化的方式读写文用格式化的方式读写文件件10.3.4 用二进制方式向文件读写一组数据用二进制方式向文件读写一组数据读写一个字符的函数读写一个字符的函数 例例10.1 从键盘输入一些字符
22、,逐个把它从键盘输入一些字符,逐个把它们送到磁盘上去,直到用户输入一个们送到磁盘上去,直到用户输入一个“”为止。为止。解题思路:用解题思路:用fgetc函数从键盘逐个输入函数从键盘逐个输入字符,然后用字符,然后用fputc函数写到磁盘文件即函数写到磁盘文件即可。可。#include#include int main()FILE*fp;char ch,filename10;printf(请输入所用的文件名:请输入所用的文件名:);scanf(%s,filename);if(fp=fopen(filename,“w”)=NULL)printf(无法打开此文件无法打开此文件n);exit(0);ch
23、=getchar();接收最后输接收最后输入的回车符入的回车符输入文件名输入文件名只写只写用用exit函数时加函数时加 printf(“请输入一个字符串请输入一个字符串(以以#结束结束):);ch=getchar();while(ch!=#)fputc(ch,fp);putchar(ch);ch=getchar();fclose(fp);putchar(n);return 0;例例10.2 将一个磁盘文件中的信息复制到另将一个磁盘文件中的信息复制到另一个磁盘文件中。一个磁盘文件中。今要求将上例建立的今要求将上例建立的file1.dat文件中的内容复制到另一个磁盘文件中的内容复制到另一个磁盘文件
24、文件file2.dat中。中。解题思路:处理此问题的算法是:从解题思路:处理此问题的算法是:从file1.dat文件中逐个读入字符,然后逐个文件中逐个读入字符,然后逐个输出到输出到file2.dat中。中。#include#include int main()FILE*in,*out;char ch,infile10,outfile10;printf(输入读入文件的名字输入读入文件的名字:);scanf(%s,infile);printf(输入输出文件的名字输入输出文件的名字:);scanf(“%s”,outfile);if(in=fopen(infile,“r”)=NULL)printf(无
25、法打开此文件无法打开此文件n);exit(0);if(out=fopen(outfile,“w”)=NULL)printf(无法打开此文件无法打开此文件n);exit(0);改为改为rb和和wb,则复,则复制一个二进制文件制一个二进制文件改为改为rb和和wb,则复,则复制一个二进制文件制一个二进制文件 while(!feof(in)ch=fgetc(in);fputc(ch,out);putchar(ch);putchar(n);fclose(in);fclose(out);return 0;检查当前读写位置检查当前读写位置是否移到文件末尾是否移到文件末尾feof()函数函数功能:功能:u用于
26、判断文件读取是否结束,如果已经读到文件结束用于判断文件读取是否结束,如果已经读到文件结束处,这时,处,这时,再进行读取操作时再进行读取操作时,feof()函数非函数非0,否则否则返回返回0./错误程序错误程序char c;while(!feof(fp)c=fgetc(fp);printf(%cn,c);/正确程序正确程序char c;c=fgetc(fp);while(!feof(fp)printf(%cn,c);c=fgetc(fp);读写一个字符串的函数读写一个字符串的函数说明:说明:fgets函数的函数原型为:函数的函数原型为:char*fgets(char*str,int n,FILE
27、*fp);u其作用是从文件读入一个字符串其作用是从文件读入一个字符串u调用时可以写成:调用时可以写成:fgets(str,n,fp);说明:说明:ufgets(str,n,fp);中中n是要求得到的字符个数是要求得到的字符个数,但实际上只读,但实际上只读n-1个字符,然后在最后加一个个字符,然后在最后加一个0字符,这样得到的字符串共有字符,这样得到的字符串共有n个字符,把个字符,把它们放到字符数组它们放到字符数组str中中u如果在读完如果在读完n-1个字符之前遇到换行符个字符之前遇到换行符“n”或文件结束符或文件结束符EOF,读入即结束,但将所遇到,读入即结束,但将所遇到的换行符的换行符“n”
28、也作为一个字符读入也作为一个字符读入u执行执行fgets成功,返回成功,返回str数组首地址,如果一数组首地址,如果一开始就遇到文件尾或读数据错,返回开始就遇到文件尾或读数据错,返回NULL说明:说明:fputs函数的函数原型为:函数的函数原型为:int fputs(char*str,FILE*fp);ustr指向的字符串输出到指向的字符串输出到fp所指向的文件中所指向的文件中u调用时可以写成:调用时可以写成:fputs(China”,fp);ufputs函数中第一个参数可以是字符串常量、函数中第一个参数可以是字符串常量、字符数组名或字符型指针字符数组名或字符型指针u字符串末尾的字符串末尾的0
29、不输出不输出,也不自动添加换行符也不自动添加换行符号。号。u输出成功,函数值为;失败,函数值为输出成功,函数值为;失败,函数值为EOF 例例10.3 从键盘读入若干个字符串,对它们从键盘读入若干个字符串,对它们按字母大小的顺序排序,然后把排好序的字按字母大小的顺序排序,然后把排好序的字符串送到磁盘文件中保存。符串送到磁盘文件中保存。解题思路:为解决问题,可分为三个步骤:解题思路:为解决问题,可分为三个步骤:u从键盘读入从键盘读入n个字符串,存放在一个二维字符个字符串,存放在一个二维字符数组中,每一个一维数组存放一个字符串;数组中,每一个一维数组存放一个字符串;u对字符数组中的对字符数组中的n个
30、字符串按字母顺序排序,个字符串按字母顺序排序,排好序的字符串仍存放在字符数组中;排好序的字符串仍存放在字符数组中;u将字符数组中的字符串顺序输出。将字符数组中的字符串顺序输出。#include#include#include int main()FILE*fp;char str310,temp10;int i,j,k,n=3;printf(“Enter strings:n”);for(i=0;in;i+)gets(stri);for(i=0;in-1;i+)k=i;for(j=i+1;j0)k=j;if(k!=i)strcpy(temp,stri);strcpy(stri,strk);strc
31、py(strk,temp);if(fp=fopen(“D:CCstring.dat”,“w”)=NULL)printf(cant open file!n);exit(0);printf(nThe new sequence:n);for(i=0;in;i+)fputs(stri,fp);fputs(“n”,fp);printf(“%sn”,stri);fclose(fp);return 0;人为地输出一个人为地输出一个n思考:思考:u从文件从文件string.dat中读回字符串,并在中读回字符串,并在屏幕上显示,应如何编写程序?屏幕上显示,应如何编写程序?#include#include int
32、 main()FILE*fp;char str310;int i=0;if(fp=fopen(“D:CCstring.dat”,“r”)=NULL)printf(cant open file!n);exit(0);while(fgets(stri,10,fp)!=NULL)printf(%s,stri);i+;fclose(fp);return 0;不用人为地输出不用人为地输出n一般调用方式为:一般调用方式为:fprintf(文件指针文件指针,格式字符串格式字符串,输出表列输出表列);fscanf(文件指针文件指针,格式字符串格式字符串,输入表列输入表列);如:如:fprintf(fp,”%d
33、,%6.2f”,i,f);fscanf(fp,”%d,%f”,&i,&f);文件读写举例文件读写举例L104.c在在D盘根目录下有文件盘根目录下有文件A.txt,该文件包含,该文件包含n行字符数据。编写程序完成如下功能:行字符数据。编写程序完成如下功能:u编写函数编写函数读取读取A.txt文件的数据。文件的数据。u编写函数,将文件中所有非数字字符以其编写函数,将文件中所有非数字字符以其ASCII值转换成数字字符,例如:值转换成数字字符,例如:A转换转换成成6和和5两个数字字符两个数字字符,并输出到屏幕上,并输出到屏幕上。u编写函数,编写函数,将将原文件中的字符以其原文件中的字符以其ASCII值
34、值输出输出到到D盘根目录下的文件盘根目录下的文件B.txt中。中。一般调用形式为一般调用形式为:fread(buffer,size,count,fp);fwrite(buffer,size,count,fp);buffer:是一个地址:是一个地址u对对fread来说,它是用来存放从文件读入的来说,它是用来存放从文件读入的数据的存储区的地址数据的存储区的地址u对对fwrite来说,是要把此地址开始的存储区来说,是要把此地址开始的存储区中的数据向文件输出中的数据向文件输出size:要读写的字节数:要读写的字节数count:要读写多少个数据项:要读写多少个数据项fp:FILE类型指针类型指针 例例1
35、0.5 从键盘输入从键盘输入10个学生的有关数据个学生的有关数据,然后把它们转存到磁盘文件上去。,然后把它们转存到磁盘文件上去。解题思路:解题思路:u定义有定义有10个元素的结构体数组,用来存放个元素的结构体数组,用来存放10个学生的数据个学生的数据u从从main函数输入函数输入10个学生的数据个学生的数据u用用save函数实现向磁盘输出学生数据函数实现向磁盘输出学生数据u用用fwrite函数一次输出一个学生的数据函数一次输出一个学生的数据#include#define SIZE 10typedef struct Student_type char name10;int num;int age
36、;char addr15;TAGSTUDENT;TAGSTUDENT studSIZE;void save()FILE*fp;int i;if(fp=fopen(stu.dat,wb)=NULL)printf(cannot open filen);return;for(i=0;iSIZE;i+)if(fwrite(&studi,sizeof(struct Student_type),1,fp)!=1)printf(file write errorn);fclose(fp);10+4+4+15=33,实际上,实际上开辟开辟36字节,是字节,是4的倍数的倍数当前路径下的文件当前路径下的文件int
37、main()int i;printf(“enter data of students:n);for(i=0;iSIZE;i+)scanf(%s%d%d%s,studi.name,&studi.num,&studi.age,studi.addr);save();return 0;为了验证在磁盘文件为了验证在磁盘文件“stu.dat”中是否中是否已存在此数据,可以用以下程序从已存在此数据,可以用以下程序从“stu.dat”文件中读入数据,然后在屏文件中读入数据,然后在屏幕上输出。幕上输出。#include#include#define SIZE 10struct Student_type char
38、 name10;int num;int age;char addr15;studSIZE;int main()int i;FILE*fp;if(fp=fopen(stu.dat,rb)=NULL)printf(cannot open filen);exit(0);for(i=0;iSIZE;i+)fread(&studi,sizeof(struct Student_type),1,fp);printf(“%-10s%4d%4d%-15sn”,studi.name,studi.num,studi.age,studi.addr);fclose(fp);return 0;如果修改例如果修改例10.4
39、:从已有的二进制文件:从已有的二进制文件“stu.list”中,读入数据并输出到中,读入数据并输出到“stu.dat”文件中,应如何修改程序?文件中,应如何修改程序?解题思路:解题思路:u编写编写load函数函数umain函数中再调用函数中再调用load函数函数void load()FILE*fp;int i;if(fp=fopen(stu_list,rb)=NULL)printf(cannot open infilen);return;for(i=0;iSIZE;i+)if(fread(&studi,sizeof(struct student_type),1,fp)!=1)if(feof(f
40、p)fclose(fp);return;printf(file read errorn);fclose(fp);int main()load();save();return 0;对文件进行顺序读写比较容易理解,也容对文件进行顺序读写比较容易理解,也容易操作,但有时效率不高易操作,但有时效率不高随机访问不是按数据在文件中的物理位置随机访问不是按数据在文件中的物理位置次序进行读写,而是可以对任何位置上的次序进行读写,而是可以对任何位置上的数据进行访问,显然这种方法比顺序访问数据进行访问,显然这种方法比顺序访问效率高得多效率高得多10.4.1 文件位置标记及其定位文件位置标记及其定位10.4.2 随
41、机读写随机读写1.文件位置标记文件位置标记为了对读写进行控制,系统为每个文为了对读写进行控制,系统为每个文件设置了一个文件读写位置标记件设置了一个文件读写位置标记(简简称文件标记称文件标记),用来指示,用来指示“接下来要接下来要读写的下一个字符的位置读写的下一个字符的位置”文件指针文件指针读写当前位置读写当前位置文件尾文件尾1.文件位置标记文件位置标记文件头文件头1.文件位置标记文件位置标记一般情况下,在对字符文件进行顺序读一般情况下,在对字符文件进行顺序读写时,文件标记指向文件开头,进行读写时,文件标记指向文件开头,进行读的操作时,就读第一个字符,然后文件的操作时,就读第一个字符,然后文件标
42、记向后移一个位置,在下一次读操作标记向后移一个位置,在下一次读操作时,就将位置标记指向的第二个字符读时,就将位置标记指向的第二个字符读入。依此类推,直到遇文件尾,结束入。依此类推,直到遇文件尾,结束1.文件位置标记文件位置标记如果是顺序写文件,则每写完一个数据如果是顺序写文件,则每写完一个数据后,文件标记顺序向后移一个位置,然后,文件标记顺序向后移一个位置,然后在下一次执行写操作时把数据写入指后在下一次执行写操作时把数据写入指针所指的位置。直到把全部数据写完,针所指的位置。直到把全部数据写完,此时文件位置标记在最后一个数据之后此时文件位置标记在最后一个数据之后1.文件位置标记文件位置标记可以根
43、据读写的需要,人为地移动了文可以根据读写的需要,人为地移动了文件标记的位置。文件标记可以向前移、件标记的位置。文件标记可以向前移、向后移,移到文件头或文件尾,然后对向后移,移到文件头或文件尾,然后对该位置进行读写该位置进行读写随机读写随机读写随机读写随机读写可以在任何位置写入数据,在可以在任何位置写入数据,在任何位置读取数据任何位置读取数据2.文件位置标记的定位文件位置标记的定位u可以强制使文件位置标记指向指定的位置可以强制使文件位置标记指向指定的位置u可以用以下函数实现:可以用以下函数实现:(1)用用rewind函数使文件标记指向文件开头函数使文件标记指向文件开头 rewind函数的作用是使
44、文件标记重新返回文函数的作用是使文件标记重新返回文件的开头,此函数没有返回值。件的开头,此函数没有返回值。例例10.5 有一个磁盘文件,内有一些信息。有一个磁盘文件,内有一些信息。要求第一次将它的内容显示在屏幕上,第要求第一次将它的内容显示在屏幕上,第二次把它复制到另一文件上。二次把它复制到另一文件上。解题思路:解题思路:u因为在第一次读入完文件内容后,文件标因为在第一次读入完文件内容后,文件标记已指到文件的末尾,如果再接着读数据记已指到文件的末尾,如果再接着读数据,就遇到文件结束标志,就遇到文件结束标志,feof函数的值等函数的值等于于1(真真),无法再读数据,无法再读数据u必须在程序中用必
45、须在程序中用rewind函数使位置指针函数使位置指针返回文件的开头返回文件的开头#includeint main()FILE*fp1,*fp2;fp1=fopen(“file1.dat”,“r”);fp2=fopen(“file2.dat”,“w”);while(!feof(fp1)putchar(getc(fp1);putchar(10);rewind(fp1);while(!feof(fp1)putc(getc(fp1),fp2);fclose(fp1);fclose(fp2);return 0;2.文件位置标记的定位文件位置标记的定位u可以强制使文件标记指向指定的位置可以强制使文件标记指
46、向指定的位置u可以用以下函数实现:可以用以下函数实现:(2)用用fseek函数改变文件标记函数改变文件标记fseek函数的调用形式为:函数的调用形式为:fseek(文件类型指针文件类型指针,位移量位移量,起始点起始点)u起始点起始点0代表代表“文件开始位置文件开始位置”,1为为“当前当前位置位置”,2为为“文件末尾位置文件末尾位置”标准指定的名字标准指定的名字位移量指以起始点为基点,向前移动的字位移量指以起始点为基点,向前移动的字节数。位移量应是节数。位移量应是long型数据型数据(在数字的在数字的末尾加一个字母末尾加一个字母L)。fseek函数一般用于二进制文件。下面是函数一般用于二进制文件
47、。下面是fseek函数调用的几个例子:函数调用的几个例子:ufseek(fp,100L,0);ufseek(fp,50L,1);ufseek(fp,-10L,2);2.文件位置标记的定位文件位置标记的定位u可以强制使文件位置标记指向指定的位置可以强制使文件位置标记指向指定的位置u可以用以下函数实现:可以用以下函数实现:(3)用用ftell函数测定文件位置标记的当前位置函数测定文件位置标记的当前位置ftell函数的作用是得到流式文件中文件位置标函数的作用是得到流式文件中文件位置标记的当前位置。记的当前位置。由于文件中的文件位置标记经常移动,人由于文件中的文件位置标记经常移动,人们往往不容易知道其
48、当前位置,所以常用们往往不容易知道其当前位置,所以常用ftell函数得到当前位置,用相对于文件开函数得到当前位置,用相对于文件开头的位移量来表示。如果调用函数时出错头的位移量来表示。如果调用函数时出错(如不存在(如不存在fp指向的文件),指向的文件),ftell函数返函数返回值为回值为-1L。例如:。例如:i=ftell(fp);if(i=-1L)printf(“errorn”);例例10.6 在磁盘文件上存有在磁盘文件上存有10个学生的数个学生的数据。要求将第据。要求将第1,3,5,7,9个学生数据输入个学生数据输入计算机,并在屏幕上显示出来。计算机,并在屏幕上显示出来。要求:从例要求:从例
49、10.4中建立的中建立的“stu.dat”中中读入数据读入数据解题思路:解题思路:u按二进制只读方式打开文件按二进制只读方式打开文件u将文件位置标记指向文件的开头,读入一个学将文件位置标记指向文件的开头,读入一个学生的信息,并把它显示在屏幕上生的信息,并把它显示在屏幕上u再将文件标记指向文件中第再将文件标记指向文件中第3,5,7,9个学个学生的数据区的开头,读入相应学生的信息,并生的数据区的开头,读入相应学生的信息,并把它显示在屏幕上把它显示在屏幕上u关闭文件关闭文件#include#include struct St char name10;int num;int age;char addr
50、15;stud10;int main()int i;FILE*fp;if(fp=fopen(“stu.dat”,“rb”)=NULL)printf(can not open filen);exit(0);for(i=0;i10;i+=2)fseek(fp,i*sizeof(struct St),0);fread(&studi,sizeof(struct St),1,fp);printf(“%-10s%4d%4d%-15sn”,studi.name,studi.num,studi.age,studi.addr);fclose(fp);return 0;1.ferror函数函数ferror函数的一