版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、显示屏和打印机是输出文件。在程序运行时,常常需要将一些数据(运行的最终结果或中间数据)输出到磁盘上存放起来(q li),以后需要时再从磁盘中输入到计算机内存。这就要用到磁盘文件。C语言把文件看作是一个字符(字节)的序列,即由一个一个字符(字节)的数据顺序组成。根据数据的组织形式,可分为ASCII文件和二进制文件。ASCII文件又称文本(text)文件,它的每一个字节放一个ASCII代码,代表一个字符。二进制文件是把内存中的数据按其在内存中的存储形式原样输出到磁盘上存放。如果有一个整数10000,在内存中占2个字节,如果按ASCII码形式输出,则占5个字节,第1页/共75页第一页,共76页。而按
2、二进制形式输出,在磁盘上只占2个字节,见图13.1。用ASCII码形式输出与字符一一对应,一个字节代表一个字符,一个字节代表一个字符,因而便于对字符进行逐个处理,也便于输出字符。但一般占存储空间较多,而且要花费转换时间(二进制形式与ASCII码间的转换)。用二进制形式输出数值,可以节省外存空间和转换时间,但一个字节并不对应一个字符,不能直接输出字符形式。一般中间结果(ji gu)数据需要暂时保存在外存上以后又需要输入到内存的,常用二进制文件保存。第2页/共75页第二页,共76页。 图13.1 由前所述,一个C文件是一个字节流或二进制流。它把数据看作是一连串的字符(z f)(字节),而不考虑记录
3、的界限。换句话说,C语言中文件并不是由记录(record)组成的(这是和PASCAL或其他高级语言不同的)。在C语言中对文件的存取是以字符(z f)(字节)为单位的。输入输出的数据流的开始和结束仅受程序控制而不受物理符号(如回车换行符)控制。第3页/共75页第三页,共76页。 也就是说,在输出时不会自动增加回车换行符以作为记录结束的标志,输入时不以回车换行符作为记录的间隔(事实上C文件并不由记录构成)。我们把这种文件称为流式文件。C语言允许对文件存取一个字符,这就增加了处理的灵活性。 在过去使用的C版本(bnbn)(如UNIX系统下使用的C)有两种对文件的处理方法:一种叫“缓冲文件系统”,一种
4、叫“非缓冲文件系统”。所谓缓冲文件系统是指系统自动地在内存区为每一个正在使用的文件名开辟一个缓冲区。从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘去。如果从磁盘向内存读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区(充满缓冲区),然后再第4页/共75页第四页,共76页。图13.2从缓冲区逐个地将数据(shj)送到程序数据(shj)区(给程序变量)。见图13.2。缓冲区的大小由各个具体的C版本确定,一般为512字节。第5页/共75页第五页,共76页。 所谓“非缓冲文件系统”是指系统不自动开辟确定大小的缓冲区,而由程序为每个文件设定缓冲区。 在UNIX系统下,用缓冲文
5、件系统来处理文本文件,用非缓冲文件系统处理二进制文件。用缓冲文件系统进行的输入输出又称为高级(或高层)磁盘输入输出(高层I/O),用非缓冲文件系统进行的输入输出又称为低级(低层)输入输出系统。ANSI C标准决定不采用非缓冲文件系统,而只采用缓冲文件系统。即既用缓冲文件系统处理文本文件,也用它来处理二进制文件。也就是(jish)将缓冲文件系统扩充为可以处理二进制文件。 在C语言中,没有输入输出语句,对文件的读写都是用库函数来实现的。ANSI规定了标准输入输第6页/共75页第六页,共76页。出函数,用它们对文件进行读写。本章只介绍ANSI C规定的文件系统以及对它的读写。13.2文件类型指针缓冲
6、文件系统中,关键(gunjin)的概念是“文件指针”。每个被使用的文件都在内存中开辟一个区,用来存放文件的有关信息(如文件的名字、文件状态及文件当前位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统定义的,取名为FILE。Turbo C在stdio.h文件中有以下的文件类型声明:第7页/共75页第七页,共76页。typedefstructshortlevel; /*缓冲区“满”或“空”的程度*/unsignedflags; /*文件状态标志*/charfd; /*文件描述符*/unsignedcharhold; /*如无缓冲区不读取字符*/shortbsize; /*缓冲区的大
7、小*/unsignedchar*baffer;/*数据(shj)缓冲区的位置*/unsignedar*curp;/*指针,当前的指向*/unsignedistemp;/*临时文件,指示器*/shorttoken;/*用于有效性检查*/FILE;第8页/共75页第八页,共76页。 有了结构体FILE类型之后,可以用它来定义若干个FILE类型的变量,以便存放若干个文件的信息。例如(lr),可以定义以下FILE类型的数组。FILEf5;定义了一个结构体数组f,它有5个元素,可以用来存放5个文件的信息。 可以定义文件型指针变量。如: FILEfp; fp是一个指向FILE类型结构体的指针变量。可以使f
8、p指向某一个文件的结构体变量,从而通过该结构体变量中的文件信息能够访问该文件。也就是说,通过文件指针变量能够找到与它相关的文件。如果有n个文件,一般应设n个指针变量(指向FILE类型结构体的指针变量),使它们分别指向第9页/共75页第九页,共76页。n个文件(确切地说指向存放该文件信息的结构(jigu)体变量),以实现对文件的访问。13.3文件的打开与关闭和其他高级语言一样,对文件读写之前应该“打开”该文件,在使用结束之后应关闭该文件。13.3.1文件的打开(fopen函数)ANSI C规定了标准输入输出函数库,用fopen()函数来实现打开文件。第10页/共75页第十页,共76页。 fope
9、n函数的调用方式通常为 FILEfp; fp=fopen(文件名,使用文件方式); 例如: fp=fopen(a1,r); 它表示要打开名字为a1的文件,使用文件方式为“读入” (r代表read,即读入),fopen函数带回指向a1文件的指针(zhzhn)并赋给fp,这样fp就和文件a1相联系了,或者说,fp指向a1文件。可以看出,在打开一个文件时,通知给编译系统以下3个信息:需要打开的文件名,也就是准备访问的文件的名字。第11页/共75页第十一页,共76页。 使用文件的方式(“读”还是“写”等)。 让哪一个指针变量指向被打开的文件。 说明: (1) 用“r”方式打开的文件只能用于向计算机输入
10、而不能用作向该文件输出数据,而且该文件应该已经存在,不能用“r”方式打开一个并不存在的文件(即输入文件),否则出错。 (2) 用“w”方式打开的文件只能用于向该文件写数据(即输出文件),而不能用来向计算机输入。如果(rgu)原来不存在该文件,则在打开时新建立一个以指定的名字命名的文件。如果(rgu)原来已存在一个以该文件名命名的文件,则在打开时将该文件删去,然后重新建立一个新文件。第12页/共75页第十二页,共76页。 (3) 如果希望向文件末尾添加新的数据(不希望删除原有数据),则应该用“a”方式打开。但此时该文件必须已存在,否则将得到出错信息。打开时,位置指针移到文件末尾。 (4) 用“r
11、+”、“w+”、“a+”方式打开的文件既可以用来输入数据,也可以用来输出数据。用“r+”方式时该文件应该已经存在,以便能向计算机输入数据。用“w+”方式则新建立一个文件,先向此文件写数据,然后(rnhu)可以读此文件中的数据。用“a+”方式打开的文件,原来的文件不被删去,位置指针移到文件末尾,可以添加,也可以读。 (5) 如果不能实现“打开”的任务,fopen函数将会带回一个出错信息。出错的原因可能是用“r”方式第13页/共75页第十三页,共76页。打开一个并不存在的文件;磁盘出故障;磁盘已满无法建立新文件等。此时fopen函数将带回一个空指针值NULL(NULL在stdioh文件中已被定义为
12、0)。常用下面的方法打开一个文件:if(fp=fopen(file1,r)=NULL)printf(cannot open this filen); exit(0); 即先检查打开的操作有否出错,如果有错就在终端上输出“cannot open this file”。exit函数的作用是关闭所有文件,终止(zhngzh)正在调用的过程。待用户检查出错误,修改后再运行。第14页/共75页第十四页,共76页。 (6) 用以上方式可以打开文本文件或二进制文件,这是ANSI C的规定,用同一种缓冲文件系统来处理文本文件和二进制文件。但目前使用的有些C编译系统可能不完全提供所有(suyu)这些功能(例如有
13、的只能用“r”、“w”、“a”方式),有的C版本不用“r+”、“w+”、“a+”,而用“rw”、“wr”、“ar”等,请读者注意所用系统的规定。 (7) 在向计算机输入文本文件时,将回车换行符转换为一个换行符,在输出时把换行符转换成为回车和换行两个字符。在用二进制文件时,不进行这种转换,在内存中的数据形式与输出到外部文件中的数据形式完全一致,一一对应。第15页/共75页第十五页,共76页。 (8) 在程序开始运行时,系统自动打开3个标准文件:标准输入、标准输出、标准出错输出。通常这3个文件都与终端相联系。因此以前我们所用(su yn)到的从终端输入或输出都不需要打开终端文件。系统自动定义了3个
14、文件指针stdin、stdout和stderr,分别指向终端输入、终端输出和标准出错输?也从终端输出)。如果程序中指定要从stdin所指的文件输入数据,就是指从终端键盘输入数据。 13.3.2文件的关闭(fclose函数) 在使用完一个文件后应该关闭它,以防止它再被误用。“关闭”就是使文件指针变量不指向该文件,第16页/共75页第十六页,共76页。也就是文件指针变量与文件“脱钩”,此后不能再通过该指针对原来与其相联系的文件进行读写操作。除非(chfi)再次打开,使该指针变量重新指向该文件。用fclose函数关闭文件。fclose函数调用的一般形式为fclose(文件指针);例如:fclose(
15、fp);前面我们曾把打开文件(用fopen函数)时所带回的指针赋给了fp,今通过fp把该文件关闭。即fp不再指向该文件。第17页/共75页第十七页,共76页。 应该养成在程序终止之前关闭所有文件的习惯,如果不关闭文件将会丢失数据。因为,如前所述,在向文件写数据时,是先将数据输到缓冲区,待缓冲区充满后才正式输出给文件。如果当数据未充满缓冲区而程序结束运行,就会将缓冲区中的数据丢失。用fclose函数关闭文件,可以避免这个问题,它先把缓冲区中的数据输出到磁盘文件,然后才释放文件指针变量。 fclose函数也带回一个(y )值,当顺利地执行了关闭操作,则返回值为0;否则返回EOF(-1)。可以用fe
16、rror函数来测试(见13.61节)。第18页/共75页第十八页,共76页。13.4文 件 的 读 写文件打开之后,就可以对它进行读写了。常用的读写函数如下所述。 13.4.1fputc函数和fgetc函数(putc函数和getc函数) 1.fputc函数把一个字符写到磁盘文件上去。其一般(ybn)调用形式为fputc(ch,fp);其中ch是要输出的字符,它可以是一个字符常量,也可以是一个字符变量。fp是文件指针变量。fputc(ch,fp)函数的作用是将字符(ch的值)输出到fp所指向的文件中去。fputc函数也带回一个值:第19页/共75页第十九页,共76页。 如果输出成功则返回值就是输
17、出的字符;如果输出失败,则返回一个EOF(-1)。EOF是在stdioh文件中定义的符号常量,值为-1。在第4章介绍过putchar函数,其实putchar是从fputc函数派生出来(ch li)的。putchar(c)是在stdio.h文件中用预处理命令#define定义的宏:#defineputchar(c)fputc(c,stdout)前面已叙述,stdout是系统定义的文件指针变量,它与终端输出相连。fputc(c瑂tdout)的作用是将c的值输出到终端。用宏putchar(c)比写fputc(c,stdout)简单一些。从用户的角度,可以把putchar(c)看作函数而不必严格地称它
18、为宏。第20页/共75页第二十页,共76页。2. fgetc函数从指定的文件读入一个字符,该文件必须是以读或读写方式打开的。fgetc函数的调用形式为ch=fgetc(fp);fp为文件型指针变量,ch为字符变量。fgetc函数带回一个字符,赋给ch。如果(rgu)在执行fgetc函数读字符时遇到文件结束符,函数返回一个文件结束标志EOF(-1)。如果(rgu)想从一个磁盘文件顺序读入字符并在屏幕上显示出来,可以:第21页/共75页第二十一页,共76页。ch=fgetc(fp); while(ch!=EOF) putchar(ch); ch=fgetc(fp); 注意:EOF不是可输出(shc
19、h)字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于-1(即EOF)时,表示读入的已不是正常的字符而是文件结束符。但以上只适用于读文本文件的情况。现在ANSI C已允许用缓冲文件系统处理二进制文件,而读入某一个字节中的二进制数据的值有可能是-1,而这又第22页/共75页第二十二页,共76页。恰好是EOF的值。这就出现了需要读入有用数据而却被处理为“文件结束”的情况。为了解决(jiju)这个问题,ANSI C提供一个feof函数来判断文件是否真的结束。feof(fp)用来测试fp所指向的文件当前状态是否“文件结束”。如果是文件结束
20、,函数feof(fp)的值为1(真),否则为0(假)。如果想顺序读入一个二进制文件中的数据,可以用while(!feof(fp) c=fgetc(fp); 第23页/共75页第二十三页,共76页。 当未遇文件结束,feof(fp)的值为0,!feof(fp)为1,读入一个字节的数据赋给整型变量c,并接着对其进行(jnxng)所需的处理。直到遇文件结束,feof(fp)值为1,!feof(fp)值为0,不再执行while循环。 这种方法也适用于文本文件。 3. fputc和fgetc函数使用举例 在掌握了以上几种函数以后,可以编制一些简单的使用文件的程序。 例13.1从键盘输入一些字符,逐个把它
21、们送到磁盘上去,直到输入一个“#”为止。第24页/共75页第二十四页,共76页。#include main() FILEfp; char ch,filename10; scanf(%s,filename); if(fp=fopen(filename,w)=NULL) printf(cannot open filen); exit(0); ch=getchar( );/*此语句(yj)用来接收在执行scanf语句(yj)时最后输入的回车符*/ ch=getchar();/*接收输入的第一个字符*/第25页/共75页第二十五页,共76页。 while(ch!=#) fputc(ch,fp);put
22、char(ch); ch=getchar(); fclose(fp); 运行情况如下:file1c (输入磁盘(c pn)文件名) computer and c#(输入一个字符串) computer and c (输出一个字符串)第26页/共75页第二十六页,共76页。 文件名由键盘输入,赋给字符(z f)数组filename,fopen函数中的第一个参数“文件名”可以直接写成字符(z f)串常量形式(如“file1c”),也可以用字符(z f)数组名,在字符(z f)数组中存放文件名(如本例所用的方法)。本例运行时,从键盘输入磁盘文件名“file1c”,然后输入要写入该磁盘文件的字符(z f
23、)“computer and c”,“#”是表示输入结束,程序将“computer and c”写到以“file1c”命名的磁盘文件中,同时在屏幕上显示这些字符(z f),以便核对。 可以用DOS命令将file1c文件中的内容打印出来:Ctype file1c computer and c第27页/共75页第二十七页,共76页。 证明了在file1c文件中已存入(cn r)了“computer and c”的信息。 例13.2将一个磁盘文件中的信息复制到另一个磁盘文件中。 #include main() FILEin,out; char ch,infile10,outfile10; print
24、f(Enter the infile name:n); scanf(%s,infile);第28页/共75页第二十八页,共76页。 printf(Enter the outfile name:n); scanf(%s,outfile); if(in=fopen(infile,r)=NULL) printf(cannot open infilen); exit(0); if(out=fopen(outfile,w)=NULL) printf(cannot open outfilen); exit(0);第29页/共75页第二十九页,共76页。 while(!feof(in)fputc(fgetc
25、(in),out); fclose(in); fclose(out); 运行(ynxng)情况如下:Enter the infile name: file1c(输入原有磁盘文件名) Enter the outfile name: file2c(输入新复制的磁盘文件名)第30页/共75页第三十页,共76页。 程序运行结果是将file1c文件中的内容(nirng)复制到file2c中去。可以用下面DOS命令验证 ctype file1c computer and c(file1c中的信息) ctype file2c computer and c(file2c中的信息) 以上程序是按文本文件方式处理
26、的。也可以用此程序来复制一个二进制文件,只需将两个fopen函数中的“r”和“w”分别改为“rb”和“wb”即可。 也可以在输入命令行时把两个文件名一起输入。这时要用到main函数的参数。程序可改为第31页/共75页第三十一页,共76页。#include main(int argc,char*argv ) FILEin,*out; char ch; if(argc!=3) printf(You forgot to enter a filenamen); exit(0); if(in=fopen(argv1,r)=NULL) printf(cannot open infilen);第32页/共7
27、5页第三十二页,共76页。 exit(0); if(out=fopen(argv2,w)=NULL) printf(cannot open outfilen); exit(0); while(!feof(in)fputc(fgetc(in),out); fclose(in); fclose(out);第33页/共75页第三十三页,共76页。 假若本程序的源文件名为a.c,经编译连接后得到的可执行文件名为a.exe,则在DOS命令工作方式下,可以输入以下的命令行: Cafile1cfile2c 即在键入可执行文件名后,再输入两个参数file1c和file2c,分别输入到argv1和argv2中,
28、argv0的内容为a,argc的值等于3(因为此命令行共有3个参数)。如果输入的参数少于3个,则程序会输出:“你忘了输入一个文件名”。程序执行结果(ji gu)是将file1c中的信息复制到file2c中。可以用以下命令验证:第34页/共75页第三十四页,共76页。Ctype file1ccomputer and c(这是file1c文件中的信息)Ctype file2ccomputer and c(这是file2c文件中的信息。可见file1c已复制到file2c中了)。最后说明一点,为了书写方便(fngbin),系统把fputc和fgetc定义为宏名putc和getc:#define pu
29、tc(ch,fp) fputc(ch,fp)#define getc(fp) fgetc(fp)第35页/共75页第三十五页,共76页。 这是在stdioh中定义的。因此,用putc和fputc及用getc和fgetc是一样的。一般可以把它们作为相同的函数来对待。 13.4.2fread函数和fwrite函数 用getc和putc函数可以用来读写文件中的一个字符。但是常常要求一次读入一组数据(例如,一个实数或一个结构体变量的值),ANSI C标准提出(t ch)设置两个函数(fread和fwrite),用来读写一个数据块。它们的一般调用形式为 fread(buffer,sie,count,fp
30、); fwrite(buffer,sie,count,fp);第36页/共75页第三十六页,共76页。 其中: buffer:是一个指针。对fread来说,它是读入数据的存放地址。对fwrite来说,是要输出数据的地址(以上指的是起始地址)。 size:要读写的字节数。 count:要进行读写多少个sie字节的数据项。 fp:文件(wnjin)型指针。 如果文件(wnjin)以二进制形式打开,用fread和fwrite函数就可以读写任何类型的信息,如: fread(f,4,2,fp); 其中f是一个实型数组名。一个实型变量占4个字节。第37页/共75页第三十七页,共76页。 这个函数从fp所指
31、向的文件读入2次(每次4个字节)数据,存储到数组f中。 如果有一个如下的结构体类型: structstudent-type char name10; int num; int age; charaddr30; stud40; 结构体数组stud有40个元素,每一个元素用来存放(cnfng)一个学生的数据(包括姓名、学号、年龄、地址)。第38页/共75页第三十八页,共76页。 假设学生的数据已存放在磁盘文件中,可以用下面的for语句和fread函数读入40个学生的数据: for(i=0;i40;i+) fread(&studi,sizeof(struct student-type),1,fp);
32、 同样,以下for语句和fwrite函数可以将内存中的学生数据输出到磁盘文件中去: for(i=0;i40,i+) fwrite(&studi,sizeof(struct student-type),1,fp); 如果fread或fwrite调用成功,则函数返回值为count的值,即输入(shr)或输出数据项的完整个数。第39页/共75页第三十九页,共76页。 下面写出一个(y )完整的程序。 例13.3从键盘输入4个学生的有关数据,然后把它们转存到磁盘文件上去。 #include #define SIZE 4 struct student-type char name10; int num;
33、 int age; char addr15;第40页/共75页第四十页,共76页。 studSIZE; void save() FILEfp; int i; if(fp=fopen(stu-list,wb)=NULL) printf(cannot open filen); return; for(i=0;iSIZE;i+)第41页/共75页第四十一页,共76页。 if(fwrite(&studi,sizeof(struct student-type),1,fp)!=1) printf(file write errorn);fclose (fp); main() int i; for(i=0;i
34、SIZE;i+) scanf(%s%d%d%s,,&studi.num,&studi.age,studi.addr);第42页/共75页第四十二页,共76页。 save(); 在main函数(hnsh)中,从终端键盘输入4个学生的数据,然后调用save函数(hnsh),将这些数据输出到以“stu_list”命名的磁盘文件中。fwrite函数(hnsh)的作用是将一个长度为29字节的数据块送到stu_list文件中(一个student_type类型结构体变量的长度为它的成员长度之和,即10+2+2+15=29)。运行情况如下:输入4个学生的姓名、学号、年龄和地址:Zhang1
35、00119room-101第43页/共75页第四十三页,共76页。 Fun 1002 20 room-102 Tan 1003 21 room-103 Ling 1004 21 room-104程序运行时,屏幕上并无输出任何信息(xnx),只是将从键盘输入的数据送到磁盘文件上。为了验证在磁盘文件“stu_list”中是否已存在此数据可以用以下程序从“stu_list”文件中读入数据,然后在屏幕上输出。#include #define SIZE 4 struct student-type第44页/共75页第四十四页,共76页。 char name10; int num; int age; cha
36、r addr15; studSIZE; main() int i; FILEfp; fp=fopen(stu-list,rb); for(i=0;iSIZE;i+)第45页/共75页第四十五页,共76页。fread(&studi,sizeof(struct student-type),1,fp); printf(%-10s %4d %4d %-15sn,,&studi.num,&studi. age,studi.addr); fclose (fp); 程序运行时不需从键盘输入任何数据。屏幕(pngm)上显示出以下信息:Zhang100119room-101Fun 1002
37、20 room-102第46页/共75页第四十六页,共76页。Tan 1003 21 room-103Ling 1004 21 room-104请注意输入输出数据的状况。从键盘输入4个学生的数据是ASCII码,也就是文本文件。在送到计算机内存时,回车和换行符转换成一个换行符。再从内存以“wb”方式(二进制写)输出到“stu_list”文件,此时不发生字符(z f)转换,按内存中存储形式原样输出到磁盘文件上。在上面验证程序中,又用fread函数从“stu_list”文件向内存读入数据,注意此时用的是“rb”方式,即二进制方式,数据按原样输入,也不发生字符(z f)转换。也就是这时候内存中的数据恢
38、复到第一个程序向第47页/共75页第四十七页,共76页。“stu-list”输出以前的情况。最后在验证程序中,用printf函数输出到屏幕,printf是格式输出函数,输出ASCII码,在屏幕上显示字符。换行符又转换为回车加换行符。如果企图从“stu_list”文件中以“r”方式读入数据就会出错。fread和fwrite函数一般用于二进制文件的输入输出。因为它们是按数据块的长度来处理输入输出的,在字符发生转换的情况下很可能出现(chxin)与原设想的情况不同。例如,如果写fread(&studi,sizeof(struct student-type),1,stdin);第48页/共75页第四十
39、八页,共76页。企图从终端键盘输入数据,这在语法上并不存在错误,编译能通过(tnggu)。如果用以下形式输入数据:Zhang 100110room-101由于fread函数要求一次输入29个字节(而不问这些字节的内容),因此输入数据中的空格也作为输入数据而不作为数据间的分隔符了。连空格也存储到studi中了,显然是不对的。这个题目要求的是从键盘输入数据,如果已有的数据已以二进制形式存储在一个磁盘文件“stu-dat”中,要求从其中读入数据并输出到“stu-list”文件中,可以编写一个load函数,从磁盘文件中读第49页/共75页第四十九页,共76页。二进制数据(shj)。void load(
40、) FILEfp; int i; if(fp=fopen(stu-dat,rb)=NULL) printf(cannot open infilen); return; for(i=0;iSIZE;i+) if(fread(&studi,sizeof(struct student-type),1,fp)!=1)第50页/共75页第五十页,共76页。 if(feof(fp)fclose (fp); return; printf(file read errorn); fclose (fp); 将load函数加到本题原来(yunli)的程序文件中,并将main函数改为main() load(); sa
41、ve(); 第51页/共75页第五十一页,共76页。13.4.3fprintf函数和fscanf函数fprintf函数、fscanf函数与printf函数、scanf函数作用相仿,都是格式化读写函数。只有一点不同:fprintf和fscanf函数的读写对象不是终端而是磁盘文件。它们的一般调用(dioyng)方式为fprintf(文件指针,格式字符串,输出表列);fscanf (文件指针,格式字符串,输入表列);例如:fprintf(fp,%d,%62f,i,t);它的作用是将整型变量i和实型变量t的值按%d和%62f的格式输出到fp指向的文件上。如果i=3,t=45,则输出到磁盘文件上的是以下
42、的字符串:第52页/共75页第五十二页,共76页。 3,450 同样,用以下fscanf函数可以从磁盘(c pn)文件上读入ASCII字符:fscanf(fp,%d,%f,&i,&t); 磁盘(c pn)文件上如果有以下字符: 3,45 则将磁盘(c pn)文件中的数据3送给变量i,45送给变量t。 用fprintf和fscanf函数对磁盘(c pn)文件读写,使用方便,容易理解,但由于在输入时要将ASCII码转换为二进制形式,在输出时又要将二进制形式转换成字符,花费时间比较多。因此,在内存与磁盘(c pn)频繁交换数据的情况下,最好不用fprintf和第53页/共75页第五十三页,共76页。
43、 fscanf函数,而用fread和fwrite函数。 13.4.4其他读写函数 1. putw和getw函数 大多数C编译系统都提供另外两个函数:putw和getw,用来对磁盘文件读写一个字(整数)。例如: putw(10,fp); 它的作用是将整数10输出到fp指向的文件。而i=getw(fp);的作用是从磁盘文件读一个整数到内存(ni cn),赋给整型变量i。 如果所用的C编译的库函数中不包括putw和getw函数,可以自己定义该两函数。putw函数如下:第54页/共75页第五十四页,共76页。putw(int i,FILE *fp) chars; s=(char*)&i; putc(s
44、0,fp);putc(s1,fp); return(i); 当调用putw函数时,如果用“putw(10,fp);”语句(yj),形参i得到实参传来的值10,在putw函数中将i的地址赋予指针变量s,而s是指向字符变量的指针变量,因此s指向i的第1个字节,s+1指向i的第2个字节。由于*(s+0)就是s0,*(s+1)就是s1,因此,s0、s1分别对应i的第1字节和第2个字节。由于第55页/共75页第五十五页,共76页。图13.313.3*(s+0)就是s0,*(s+1)就是s1,因此,s0、s1分别对应i的第1字节和第2字节。顺序输出s0、s1就相当于输出了i的两个(lin )字节中的内容。
45、见图13.3。第56页/共75页第五十六页,共76页。 getw函数如下: getw(FILE *fp) chars; int i; s=(char *)&i;/*使s指向i的起始地址*/ s0=getc(fp); s1=getc(fp); return(i); putw和getw并不是ANSI C标准定义的函数。但许多(xdu)C编译都提供这两个函数,但有的C编译可能不第57页/共75页第五十七页,共76页。以putw和getw命名此两函数,而用其他函数名,请用时注意。2. 读写其他类型数据如果用ANSI C提供的fread和fwrite函数,读写任何类型数据都是十分方便的。如果所用的系统不
46、提供这两个函数,用户只好(zhho)自己定义所需函数。例如,可以定义一个向磁盘文件写一个实数(用二进制方式)的函数putfloat:putfloat(float num,FILE *fp) chars;第58页/共75页第五十八页,共76页。 int count; s=(char *)# for(count=0;count4;count+) putc(scount,fp); 同样(tngyng)可以编写出读写任何类型数据的函数。3. fgets函数和fputs函数fgets的作用是从指定文件读入一个字符串。如:fgets(str,n,fp);n为要求得到的字符,但只从fp指向的文件输入
47、n-1个字符,然后在最后加一个0字符,因此得到第59页/共75页第五十九页,共76页。的字符串共有n个字符。把它们放到字符数组str中。如果在读完n-1个字符之前遇到换行符或EOF,读入即结束。fgets函数返回值为str的首地址。fputs函数的作用是向指定的文件输出一个字符串。如:fputs(China,fp);把字符串“China”输出到fp指向的文件。fputs函数中第一个参数可以是字符串常量、字符数组名或字符型指针。字符串末尾的0 不输出。若输出成功,函数值为0;失败时,为EOF。这两个函数类似以前介绍过的gets和puts函数,只是(zhsh)fgets和fputs函数以指定的文件
48、作为读写对象。第60页/共75页第六十页,共76页。13.5文 件 的 定 位文件中有一个位置指针,指向当前读写的位置。如果顺序读写一个文件,每次读写一个字符,则读写完一个字符后,该位置指针自动移动指向下一个字符位置。如果想改变这样的规律,强制使位置指针指向其他指定的位置,可以用有关函数。13.5.1rewind函数rewind函数的作用(zuyng)是使位置指针重新返回文件的开头。此函数没有返回值。例13.4有一个磁盘文件,第一次将它的内容显示在屏幕上,第二次把它复制到另一文件上。第61页/共75页第六十一页,共76页。#include main() FILEfp1,*fp2; fp1=fo
49、pen(file1c,r); fp2=fopen(file2c,w); while(!feof(fp1)putchar(getc(fp1); rewind(fp1); while(!feof(fp1)putc(getc(fp1),fp2); fclose(fp1);fclose(fp2); 在第一次将文件的内容显示(xinsh)在屏幕以后,文件file1c的位置指针已指到文件末尾,feof的值为非零(真)。执行rewind函数,使文件的位置指针重第62页/共75页第六十二页,共76页。新定位于文件开头,并使feof函数的值恢复为0(假)。13.5.2fseek函数和随机读写对流式文件可以进行(
50、jnxng)顺序读写,也可以进行(jnxng)随机读写。关键在于控制文件的位置指针,如果位置指针是按字节位置顺序移动的,就是顺序读写。如果能将位置指针按需要移动到任意位置,就可以实现随机读写。所谓随机读写,是指读写完上一个字符(字节)后,并不一定要读写其后续的址?字节),而可以读写文件中任意所需的字符(字节)。用fseek函数可以实现改变文件的位置指针。第63页/共75页第六十三页,共76页。 fseek函数(hnsh)的调用形式为fseek(文件类型指针,位移量,起始点) “起始点”用0、1或2代替,0代表“文件开始”,1为“当前位置”,2为“文件末尾”。ANSI C标准指定的名字如表13.
51、2所示。 “位移量”指以“起始点”为基点,向前移动的字节数。ANSI C和大多数C版本要求位移量是long型数据。这样当文件的长度大于64时不致出问题。ANSI C标准规定在数字的末尾加一个字母L,就表示是long型。 下面是fseek函数(hnsh)调用的几个例子: fseek(fp,100L,0);将位置指针移到离文件头100个字节处第64页/共75页第六十四页,共76页。 fseek(fp,50L,1); 将位置指针移到离当前位置50个字节处 fseek(fp,-10L,2); 将位置指针从文件末尾处向后退10个字节 利用fseek函数就可以实现随机读写了。 例13.5在磁盘(c pn)
52、文件上存有10个学生的数据。要求将第1、3、5、7、9个学生数据输入计算机,并在屏幕上显示出来。 程序如下: #include第65页/共75页第六十五页,共76页。 struct student-type char name10; int num; int age; char sex; stud10; main() int i; FILE *fp;第66页/共75页第六十六页,共76页。 if(fp=fopen(stud -dat,rb)=NULL) printf(can not open filen); exit(0); for(i=0;i10;i+=2) fseek(fp,i*sizeof(struct student-type),0); fread(&studi, sizeof(struct student-type),1,fp);第67页/共75页第六十七页,共76页。 printf(%s %d %d %cn,,studi.num,studi.age,studi.sex); fclose(fp); 13.5.3ftell函数ftell函数的作用是得到流式文件中的当前位置,用相对(xingdu)于文件开头的位移量来表示。由于文件中的位置指针经常移动,人们往往不容易知道其当前位置
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 北理工通信课程设计
- OCR身份证数据清洗课程设计
- 超声波测距报警创新设计课程设计
- 图像灰度化与边缘检测程序设计思路课程设计
- 基于IoT的智慧养老监护系统设计案例课程设计
- 生物特征认证系统设计要点课程设计
- 基于模拟退火的车间调度优化进展课程设计
- 基于SPI的控制器应用课程设计
- 初中班会课程设计
- 拨叉课程设计夹具
- 新高考物理一轮复习分层提升练习专题19 板块模型(原卷版)
- 学校食堂餐饮服务投标方案(技术方案)
- 翻译人员派遣协议范本
- GB/T 7744-2023工业氢氟酸
- 企业网络安全建设PPT完整全套教学课件
- 老年人辅助器具应用高职PPT完整全套教学课件
- 消费者行为学之自我概念与生活方式概述
- 把未来点亮歌词打印版
- 工艺变更履历表
- 五年级分数乘除法计算题
- 白银刘川工业集中区化工园区总体规划(2022-2035)环境影响评价报告书
评论
0/150
提交评论