《C程序设计》课件第10章_第1页
《C程序设计》课件第10章_第2页
《C程序设计》课件第10章_第3页
《C程序设计》课件第10章_第4页
《C程序设计》课件第10章_第5页
已阅读5页,还剩66页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第十章文件10.1文件概述10.2文件的打开与关闭10.3文件的读/写10.4文件的定位10.5程序设计举例习题10.1文件概述10.1.1文件的概念磁盘文件在DOS管理中被定义为存储在外部介质上的程序或数据的集合,是一批逻辑上有联系的数据(如一个程序、一批实验数据、一篇文章或一幅图像等)。每个文件都有一个文件名作为标识,每个文件在磁盘中的具体存放位置、格式都由操作系统中的文件系统管理,也就是说,操作系统是以文件为单位对程序或数据进行管理的。我们最熟悉的是编辑后存于磁盘上的源程序文件*.C,经编译后得到的目标文件*.OBJ,连接之后形成的可执行文件*.EXE等。我们只需告诉操作系统一个文件名,就可利用DOS命令或Windows的资源管理器对文件进行读、写、删除、拷贝、显示或打印等工作。在C语言中文件的含义更为广泛,不仅包含以上所述的磁盘文件,还包括一切能进行输入/输出的终端设备,它们被看成是设备文件。如键盘常称为标准输入文件,显示器称为标准输出文件。文件是由磁盘文件和设备文件组成的。作为磁盘文件之一的数据文件是本章学习的主要对象。根据文件内数据的组织形式,文件可分为文本(text)文件和二进制文件。文本文件又称为ASCII码文件,这种文件在磁盘中存放时每个字节存放一个字符的ASCII码。ASCII码文件可在屏幕上按字符显示,文件的内容可以通过编辑程序(如记事本等)进行建立和修改,人们能读懂文件内容。但是ASCII码文件所占存储空间较多,处理时要花费转换时间(内存中的二进制形式与ASCII码之间的转换)。二进制文件是将数据按其在内存中的二进制形式直接存入文件。这种形式可以节省存储空间,减少转换时间,在读/写大批数据时速度较快,一般中间结果数据常用二进制文件保存。但二进制文件不能直接输出字符形式,所以不便于阅读。整数5678在两种不同文件中的存储形式如图10.1所示。从图中可看出,整数5678在ASCII码文件中占用了4个字节,而在二进制文件中只占用了2个字节。图10-1整数在不同文件中的存储形式10.1.2数据流在使用C语言编写应用程序时,也可以利用操作系统来处理以文件形式存放在磁盘上的数据。操作系统直接管理文件时,一般是将文件作为一个整体来处理的,例如拷贝文件、删除文件等,而用C编写的应用程序往往要对文件的内容进行处理。文件的内容可能千变万化,文件的大小也各不相同,那么如何处理文件中的数据呢?为此,C语言的输入/输出系统引入了“流”(stream)的概念:在编程者和文件(包括终端设备)之间提供了一种抽象的概念——数据流,这也是基于Windows编程(进行输入/输出)的基本概念,所以要深入理解数据流的概念。数据流是对数据输入/输出(I/O)行为的一种抽象。各种各样的终端设备或磁盘文件的细节是非常复杂多样的(例如磁盘文件既允许顺序存取,又允许随机存取,而作为终端的设备文件就只能顺序存取),直接对它们编程将会非常繁琐。引入数据流的概念有效地解决了这一难题。只要建立了输入/输出数据流,编程者在应用程序中就不需要关心底层输入/输出设备或是任何磁盘文件的具体细节差异。程序中要输入数据,只需从输入数据流中读入;输出数据只需向输出数据流中写出即可,这样就使程序完全与具体硬件资源脱离了关系,也就是说数据流使C程序与具体系统完全不相关,使C程序可以非常方便地移植。数据流可分为文字流和二进制流。一个文字流是一行行的字符,换行符表示这一行的结束。文字流中某些字符的变换由环境工具的需要来决定。例如一个换行符可以变换为回车换行两个字符。因此所读/写的字符与外部设备中的数据没有一一对应的关系。一个二进制流是由与外部设备中的数据一一对应的一系列字节组成的。使用中没有字符翻译过程,而且所读/写的字节数目也与外部设备中的数目相同。在一个程序开始执行时,三个预定义的文字流:stdin(标准输入)、stdout(标准输出)和stderr(标准出错)就被打开,有的系统还同时打开stdprn(标准打印机)和stdaux(标准辅助设备,大多数系统是控制台)。对编程人员来说,所有的I/O通过流来进行。所有的流都一样,都是一系列字符。文件I/O系统把流与文件,也就是与有I/O功能的外部设备连接起来。C语言的I/O库函数把来自设备的源信息转换到流之中,或反过来把流中的信息转换给各设备。在C语言中,编程者只需记住流这个概念,只使用一个文件系统就可以完成全部的I/O操作。10.1.3C的文件系统及其与流的关系

C的文件系统可分为缓冲文件系统和非缓冲文件系统两类。所谓缓冲文件系统,又称高级磁盘输入/输出系统。在调用这种文件处理函数时,会自动在用户内存区中为每一个正在使用的文件划出一片存储单元,称为开辟一个缓冲区。设立缓冲区的原因是磁盘的读/写速度比内存的处理速度要慢很多,而且磁盘驱动器是机电设备,定位精度比较差,所以磁盘数据存取要以扇区(磁盘上某磁道中的一个弧形段,通常存放固定数量的数据)或者簇(由若干扇区组成)为单位。这样就要求有一个缓冲区来作为文件数据输入/输出的中间站来协调:从磁盘文件中读取数据时,先将含有该数据的扇区或簇从磁盘文件以慢速读到缓冲区中,然后再从缓冲区将数据快速送到应用程序的变量中去。下次再读数据时,首先判断缓冲区中是否还有数据,如果有,则直接从缓冲区中读,否则就要从磁盘中再读另一个扇区或簇。向磁盘中写数据也一样,数据总是先从内存写入缓冲区中,直到缓冲区写满之后才一起送到磁盘文件中。前面学过的getchar()函数是类似的缓冲输入方式,读者可参考第三章中的相应程序单步跟踪其执行过程,体会缓冲文件的实质。非缓冲文件系统又称为低级磁盘输入/输出系统。系统不为这类文件自动提供文件缓冲区,文件读/写函数也与缓冲文件系统不同。因其不是ANSIC规定的范围,又用得不多,故本书只介绍缓冲文件系统的有关知识。

C语言中将缓冲文件看成是流式文件,即无论文件的内容是什么,一律看成是由字符(文本文件)或字节(二进制文件)构成的序列,即字符流。流式文件的基本单位是字节,磁盘文件和内存变量之间的数据均以字节为基础。若实际数据的划分是结构体类型的数据块,可通过一次读/写多个字节来实现。流式文件的好处也就是应用数据流的好处,即对各种文件编程时不必去关心具体设备的复杂情况或各种磁盘文件的具体格式,只需单纯地与数据流交换数据即可达到与各种具体设备交换数据或处理各种具体文件的目的。具体地讲,读一个字符即是从数据流中拷贝一个字符到内存中;写一个字符,就是将内存中的一个字符拷贝到数据流中。至于数据真正从何处“流”来或“流”向何处,编程者只需在程序的最初将数据流与具体的硬件资源或磁盘文件联系起来即可确定,其后的具体操作中编程者只需调用读/写函数,而不必考虑具体设备或文件间的差异。这样非常有利于编出统一的、易移植的程序。例如,我们从一开始学的输入/输出函数,为什么可以直接调用scanf()函数从键盘读入数据,调用printf()函数就可以在CRT上显示数据呢?程序里没有任何参数提及键盘或显示器,这是因为程序运行之初即自动打开三个文件将数据流定向于键盘和显示器(这是系统的缺省设置),这样应用程序就可以直接实现从键盘输入数据或向显示器输出数据了。磁盘文件不同于设备文件之处在于必须在程序中调用打开函数来打开文件,即用一个文件打开操作使数据流和一个特定的文件发生联系。一旦一个文件被正确打开,应用程序就可以通过一个数据流与该文件之间交换信息。完成任务后,应用程序又必须关闭文件,即用一个文件关闭操作切断数据流与磁盘文件间的联系,也就是使数据流脱离一个具体的文件。10.1.4文件指针一般缓冲文件操作有三个必需的步骤:

(1)在使用文件前要调用打开函数将文件打开,若打开失败,则返回一个空指针;若打开正常,可以得到一个文件指针,并利用它继续对文件操作。

(2)可调用各种有关函数,利用该指针对文件进行具体处理,一般要对文件进行读或写操作。

(3)在文件用完时,应及时调用关闭函数来关闭文件,切断数据流,防止数据遗失或误操作破坏文件内容。缓冲文件系统中,关键的概念是文件指针。通常,由于文件中的数据很多,因此读/写时应该指明对哪个数据进行操作。流式文件中采用的方法是设立一个专门用来存放文件读/写位置的变量,称为当前工作指针。在对某文件开始进行操作时,将当前工作指针的值设置为0,表示文件从头开始读(写);每次读(写)之后,自动将当前工作指针的值加上本次读(写)的字节数,作为下次读(写)的位置。从前面的介绍可以看出,要对一个文件进行操作,除了要设当前工作指针,还必须管理缓冲区。实际上,在头文件stdio.h中,定义了一个名为FILE的类型,包含了所有与文件操作有关的数据成员,这个文件类型是文件处理的基础。文件类型FILE不是C语言的新类型,它是用typedef定义出来的有关文件信息的一种结构体类型。如TurboC的stdio.h文件中有如下的定义:

typedefstruct

{

short level;/*缓冲区“满”或“空”的程度*/unsigned flags;/*文件状态标志*/char fd;/*文件描述符*/unsignedchar hold;/*如无缓冲区不读取字符*/short bsize;/*缓冲区的大小*/unsignedchar *buffer;/*数据缓冲区的位置*/unsignedchar *curp;/*当前工作指针*/unsigned istemp;/*临时文件,指示器*/short token;/*用于有效性检查*/

}FILE;有了FILE类型之后,可以定义文件型指针。如“FILE*fp;”,fp是一个文件型的指针,将指向某个文件,即指向FILE型的结构体型变量中有关文件的信息,通过这些信息能够找到与它相关的文件。如果有n个文件,一般应设n个文件指针,使它们分别指向n个文件,以实现对文件的访问。实际上,文件指针就可以理解为数据流。设了一个文件型指针,然后将打开文件时返回的具体文件的首地址赋给该指针,就建立起了程序与文件间的数据流,后续的程序对该文件的一切操作只需针对此指针操作,即脱离具体的文件,只面向数据流操作。在完成具体的文件操作之后,关闭文件时,就切断了该文件型指针与文件间的联系,此指针不再指向那个文件,也就是切断了该文件的数据流。10.2文件的打开与关闭

C语言中,没有输入/输出语句,对文件的操作都是用库函数来实现的。下面将介绍缓冲文件系统的打开和关闭函数。10.2.1文件的打开(fopen()函数)

打开函数fopen()的调用方式是:

FILE*fp;

fp=fopen(文件名,使用文件方式);例如,

fp=fopen("A1.DAT","r");它表示,要打开名字为A1.DAT的文件,使用文件方式为“读入”,fopen()函数带回指向A1.DAT文件的指针并赋给fp,这样fp就和A1.DAT相联系了,或者说,fp指向A1.DAT文件。可以看出,在打开一个文件时,将给编译系统通知以下三个信息:

(1)需要打开的文件名。也就是准备访问的文件的名字。

(2)使用文件的方式(读还是写等)。

(3)让哪一个指针变量指向被打开的文件。文件使用方式见表10.1。表10.1文件使用方式说明:

(1)表中所用字母分别为单词read,write,append,binary或其组合词的首字母。

(2)用"r"方式打开的文件只能用于从该文件中读出数据至计算机的内存变量中,而不能用作向该文件写数据。而且该文件应该已经存在,不能用"r"方式打开一个并不存在的文件。

(3)用"w"方式打开的文件只能用于向该文件写数据,而不能用来从文件中读出数据。如果原来不存在该文件,则在打开时新建立一个按指定名字命名的文件。如果原来已存在一个以该文件名命名的文件,则在打开时将该文件删去,然后重新建立一个新文件。

(4)如果希望向文件末尾添加新的数据(不希望删除原有数据),则应该用"a"方式打开,但此时该文件必须存在,否则将得到出错信息。打开时,位置指针将移到文件末尾。

(5)用"r+","w+","a+"方式打开的文件可以用来输入和输出数据。用"r+"方式时该文件应该已经存在,以便能向计算机输入数据。用"w+"方式则新建立一个文件,先向此文件写数据,然后可以读此文件中的数据。用"a+"方式打开的文件,原来的文件不被删去,位置指针移到文件末尾,可以添加也可以读。

(6)如果不能实现“打开”的任务,fopen()函数将会带回一个出错信息。出错的原因可能是用"r"方式打开了一个并不存在的文件、磁盘出故障或磁盘已满无法建立新文件等。此时,fopen()函数将带回一个空指针值NULL(NULL在stdio.h文件中已被定义为0)。常用下面的程序段打开一个文件:

if((fp=fopen("filel","r"))==NULL){

printf("Cannotopenthisfile\n");

exit(0);

}即先检查打开操作是否正确,如果有错就在终端上输出“Cannotopenthisfile”。

exit()函数的作用是关闭所有文件,终止正执行的程序。待程序员检查出错原因,修改后再运行。

(7)用以上方式可以打开文本文件或二进制文件,这是标准C的规定,用同一种缓冲文件系统来处理文本文件和二进制文件。但目前使用的有些C编译系统可能不完全提供所有这些功能,例如有的只能用"r"、"w"、"a"方式,有的C版本不用"r+"、"w+"、"a+",而用"rw"、"wr"、"ar"等。请读者注意所用系统的规定。

(8)在用文本文件向计算机输入数据时,将回车换行符转换为一个换行符,在输出时把换行符转换成回车和换行两个字符。在用二进制文件时,不进行这种转换,内存中的数据形式与输出到外部文件中的数据形式完全一致,一一对应。10.2.2文件的关闭(fclose()函数)

在使用完一个文件后应该调用fclose()函数关闭文件。

fclose()函数的调用格式为fclose(文件指针)。例如“fclose(fp);”就表示把指针fp所指的文件关闭了,也就是断开了打开文件时建立的数据流——fp与具体文件的联系,即不能再通过fp对某个具体文件进行操作。如果在程序终止之前不关闭文件,将可能丢失缓冲区中最后一批未处理的数据,因为fclose()函数的调用不仅释放文件指针,还刷新缓冲区。fclose()函数将缓冲区中可能遗留的未装满送走的数据输入内存或输出至磁盘文件,以确保数据不丢失。当然,程序结束时会自动关闭文件,但用完文件后及时关闭是一个好的编程习惯。

fclose()函数也返回一个值:0表示顺利返回,非0表示关闭错误。10.3文件的读/写10.3.1fputc()函数和fgetc()函数

fputc()函数的调用形式为:

fputc(ch,fp);该函数的作用是将字符(ch的值)输出到fp所指向的文件中。其中ch是要输出的字符,它可以是一个字符常量,也可以是一个字符变量。fp是文件指针,它是从fopen()函数得到的返回值。fputc()函数也带回一个值,如果输出成功,则返回值就是输出的字符;如果输出失败,则返回一个EOF。EOF是在stdio.h文件中定义的符号常量,值为-1。

fgetc()函数的调用形式为:

ch=fgetc(fp);该函数的作用是从指定文件读入一个字符,该文件必须是以读或读/写方式打开的。其中fp为文件型指针,指向所打开备读的文件;ch为字符变量,接收fgetc()函数带回的字符。如果在执行fgetc()读字符时遇到文件结束符,函数则返回一个文件结束标志EOF,可以利用它来判断是否读完了文件中的数据。如想从一个磁盘文件按顺序读入字符并在屏幕上显示出来,可编程为:

while((ch=fgetc(fp))!=EOF)

putchar(ch);注意,EOF不是可输出字符,因此在屏幕上显示不出来。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于-1(即EOF)时,表示读入的已不是正常的字符而是文件结束符。但以上只适用于读文本文件。现在标准C已允许用缓冲文件系统处理二进制文件,读入某一个字节中的二进制数据的值有可能是-1,而这又恰好是EOF的值。这就出现了读入有用数据却被处理为“文件结束”的情况,即终止符设置不恰当。为了解决这个问题,标准C提供了一个feof()函数来判断文件是否真的结束。feof(fp)用来测试fp所指向的文件当前状态是否为“文件结束”,如果是文件结束,函数feof(fp)的值为1(真),否则为0(假)。例如,顺序读入一个二进制文件中的数据的程序段如下:

while(!feof(fp))

{

c=fgetc(fp);

}当未遇文件结束时,feof(fp)的值为0,!feof(fp)为1,读入一个字节的数据赋给变量c(接着可做其它处理),之后再求feof(fp)函数,循环工作直到文件结束,feof(fp)值变为1,!feof(fp)值为0,结束while循环。这种方法也适用于文本文件。在掌握了以上几种函数以后,可以编制一些简单的使用文件的程序,下面是一文件建立的例子。

例10.1

建立一个磁盘文件,将键入的回车前的若干个字符逐个写入该文件。

#include<stdio.h>

voidmain()

{

FILE*fp;

charch,filename[13];

printf("\nInputthefile\′sname:");

gets(filename);/*注1*/

if((fp=fopen(filename,"w"))==NULL){

printf("Cannotopenthefile\n");

exit(0);

}

printf("Inputthecharacterstothefile:\n");

while((ch=getchar())!=′\n′)

/*注2*/{

fputc(ch,fp); /*注3*/

putchar(ch); /*注4*/}fclose(fp);

}运行情况如下:

Inputthefile′sname:fileex1.dat↙

(注1要求的输入磁盘文件名)

Inputthecharacterstothefile:

Whatinsidethefile↙

(注2要求的键入一个字符串)

Whatinsidethefile

(注4输出到显示器上的字符串,与写入文件的内容一样,以资核对)程序运行之后,可以查看文件目录,将多出一个名为fileex1.dat的数据文件,可用DOS命令将其内容打印出来:

typefileex1.dat↙Whatinsidethefile (由注3行循环写入的)由上例可以看出,文件指针就是通向文件的数据流。当打开一个文件,执行fp=fopen(…)时,就将一个数据流与该文件联系起来,其后对文件的操作都是对此文件指针fp的操作,即“脱离”具体文件,只通过对数据流的操作,完成对相应文件的操作。此后的程序直到执行相应的fclose(fp)函数之时,文件指针fp相当于该具体文件的全权代表。执行相应的fclose()函数时,关闭文件,就切断了该文件与此数据流之间的联系。10.3.2fgets()函数和fputs()函数

fgets()函数是从指定文件读入一个字符串,其调用形式如下:

fgets(str,n,fp);该函数的功能是从fp指向的文件读入n-1个字符,并把它们放到字符数组str(也可以是字符指针)中,如果在读入n-1个字符结束之前遇到换行符或EOF,读入即结束。字符串读入在最后加一个′\0′字符,fgets()函数返回值为str的首地址。

fputs()函数是向指定的文件输出一个字符串,其调用形式如下:

fputs(str,fp);该函数将字符串输出到fp指向的文件。其中str可以是字符串常量、字符数组名或字符指针。若函数调用成功,返回0,否则返回非0值。例如:fputs(“China”,fp);即将字符串"China"输出到fp指向的文件。这两个函数类似以前介绍过的gets()和puts()函数,只是fgets()和fputs()函数以指定的文件作为读/写对象。10.3.3fprintf()函数和fscanf()函数

fprintf()函数、fscanf()函数与printf()和scanf()函数的作用类似,都是格式化读/写函数。前二者的读/写对象是磁盘文件,而后二者是终端设备。所以前二者函数调用参数中要多出一代表文件的文件指针。一般调用方式为:

fprintf(文件指针,控制字符串,参量表);

fscanf(文件指针,控制字符串,参量表);下例说明了这两种函数的用法。例10.2

按格式键入字符型、整型、实型各一数,写入文件dform.dat,再读出送显。

#include<stdio.h>

voidmain()

{

inti,i1;

charch,ch1;

floatf,f1;

FILE*fp;

printf("\nInputchif:");

scanf("%c%d%f",&ch,&i,&f);

if((fp=fopen(“dform.dat”,“w”))==NULL)

/*注1*/

{

printf("Cannotopenthefile\n");

exit(0);

}

fprintf(fp,"%c%5d%4.1f",ch,i,f);/*注2*/

fclose(fp);/*注3*/

if((fp=fopen("dform.dat","r"))==NULL)

{

printf("Cannotopenthefile\n");

exit(0);

}

fscanf(fp,"%c%d%f",&ch1,&i1,&f1);

printf("%c%5d%4.1f",ch1,i1,f1);

fclose(fp);

}分析:注1行为写打开文本文件dform.dat;注2行即为格式化写函数调用,将三数写入文件;注3行是在写操作完成之后关闭文件,若无此关闭操作,三数只能留在缓冲区中,而未真正写到文件中。虽然其后接着要读同一个文件,也仍然由fp指向,但此前的fp指向的是为写打开的dform.dat,要想读此文件,还必须再以读的形式打开,再由fp指向。程序运行情况:

Inputchif:a22.2↙ (提示及输入)

a└┘└┘└┘└┘22.2 (屏幕显示)

dform.dat中的内容同屏显。10.3.4fread()函数和fwrite()函数用fprintf()和fscanf()函数对磁盘文件读/写,使用方便,容易理解,但由于在输入时要将ASClI码转换为二进制形式,在输出时又要将二进制形式转换成字符,花费时间比较多。再者,格式读/写只能面向数据项,对于结构体类型的变量则要一个一个成员地输入/输出,程序编写比较繁琐。因此,当文件内的数据以结构体类型组织或内存与磁盘频繁交换数据时,最好不用fprintf()和fscanf()函数,而用成对读/写函数fread()和fwrite()。

fread()和fwrite()的一般调用形式为:

fread(buffer,size,count,fp);

fwrite(buffer,size,count,fp);其中:buffer是一个地址。对fread来说,它是读入数据将要存放处的地址。对fwrite()来说,是要输出数据的地址。

size是要读/写的一个数据块的字节数。

count是要进行读/写数据块的个数。

fp是文件指针,指向待读或写的文件。如果函数调用成功,则函数返回为count的值,即输入或输出数据项的完整个数;否则出错。如果文件以二进制形式打开,则用fread()和fwrite()函数就可以读/写任何类型的信息。例如:

fread(f,4,2,fp);其中,f是一个实型数组名。一个实型变量占4个字节。这个函数从fp所指向的文件读入2次(每次4个字节)数据,存储到数组f中。下面以一文件建立为例说明一结构体变量的整体写入。例10.3

建立一个有关工人工资的数据文件。

#include<stdio.h>

#defineSIZE6

structstaff

{

charname[10];

intsalary;

intcost;

}worker[SIZE];

voidsavef()

{

FILE*fp;

inti;

if((fp=fopen("work.dat","wb"))==NULL)

/*以二进制只写方式打开文件*/{

printf("Cannotopenthefile\n");

return;

}

for(i=0;i<SIZE;i++)

if(fwrite(&worker[i],sizeof(structstaff),1,fp)!=1)

/*写数据到文件中*/

printf("Filewriteerror\n");

fclose(fp);

}

voidmain(){

inti;

printf("\nInput%dworker\′snamesalarycost:\n",SIZE);

for(i=0;i<SIZE;i++)

scanf("%s%d%d",worker[i].name,&worker[i].salary,&worker[i].cost);

savef();

}10.4文件的定位前面已介绍过:文件中有一个位置指针指向下一个要读的数据,称为当前工作指针。每读/写完一个数据,该位置指针即自动向后移动一个数据的位置,指向了下一个要读/写的数据,这就是顺序读/写。但实际处理中,常常要求随机读/写或多次反复读/写,就要调用有关函数,强制位置指针指向其它位置。10.4.1rewind()函数

rewind()函数可以强制使当前工作指针指向文件的开头。一般在要重新从头读/写文件时使用。如下例,在读了文件dfr.dat一遍送显示器后,文件的位置指针已移到文件的最后,为了重新读一遍再写到文件dfw.dat中,必须先执行一次rewind()函数,才能正确读出。例10.4

将已建好的文件dfr.dat的内容顺序读一遍送显示器,再读一遍复制到文件dfw.dat中。

#include<stdio.h>

voidmain()

{

inti;

charch;

floatf,f1;

FILE*fp1,*fp2;

if((fp1=fopen("dfr.dat","r"))==NULL)

/*以只读方式打开文本文件*/

{

printf("Cannotopenthefileforreading\n");

exit(0);

}

if((fp2=fopen("dfw.dat","w"))==NULL)

/*以只写方式打开文本文件*/

{

printf("Cannotopenthefileforwriting\n");

exit(0);

}

fscanf(fp1,"%c%d%f",&ch,&i,&f);

printf("%c,%5d,%4.1f\n",ch,i,f);

rewind(fp1);

/*使当前文件的位置指针指向文件开头*/

fscanf(fp1,"%c%d%f",&ch,&i,&f1);

fprintf(fp2,“%c%d%f”,ch,i,f1);

/*写数据到文件中*/

fclose(fp1);

fclose(fp2);

}若将例10.2产生的dform.dat拷贝为dfr.dat,则程序运行后,屏幕显示为:

a,2,2.2所建立的dfw.dat文件的内容为a22.200000。10.4.2fseek()函数利用fseek()函数可以控制文件位置的指针进行随机读/写。

fseek()函数的调用形式如下:

fseek(文件类型指针,位移量,起始点);起始点可按表10.2中规定的方式取值,既可以用标准C规定的常量名,也可以用对应的数字。位移量指从起始点向前移动的字节数。

fseek()函数一般用于二进制文件,因为文本文件要发生字符转换,计算位置时容易发生混乱。下面是一个文件随机读/写的例子。表10.2指针起始点的表示例10.5

将例10.3形成的职工数据文件中的第1、3、5个工人的信息读出、送显。

#include<stdio.h>

#defineSIZE6

structstaff

{

charname[10];

intsalary;

intcost;

}worker[SIZE];

voidmain()

{

FILE*fp;

inti;

if((fp=fopen("work.dat","rb"))==NULL)/*以只读方式打开二进制文件*/

{

printf("Cannotopenthefile\n");

exit(0);

}

for(i=0;i<SIZE;i++,i++)

{

fseek(fp,i*sizeof(structstaff),0);

fread(&worker[i],sizeof(structstaff),1,fp);

/*从文件中读出的数据存入结构体数组*/

printf(“%s%d%d\n”,worker[i].name,

worker[i].salary,worker[i].cost);

}

fclose(fp);

}若形成work.dat文件时的输入数据为:

Li11100100↙

Li21200200↙

Li31300300↙

Li41400400↙

Li51500500↙

Li61600600↙则此程序的运行结果为:

Li11100100

Li31300300

Li5150050010.4.3ftell()函数

ftell()函数的作用是得到流式文件中位置指针的当前位置,用相对于文件开头的位移量来表示。由于文件的位置指针经常移动,往往不易搞清其当前位置,用ftell()函数可以返回其当前位置,若返回-1L,表示函数调用出错。例如:

i=ftell(fp);

if(i==-1L)printf("error\n");有关文件的处理函数还有很多,读者可查看附录二。初学者往往感到文件编程难,主要是对文件的概念比较陌生所致。其实,文件的编程并不是很难,只是在过去的数据处理程序的前后加上些有关文件的“套子”罢了,而这些有关文件的“套子”是相对程式化的。如果掌握了本书前面各章节的知识,只需记住有关文件的函数,理解文件的概念和处理步骤,再加上些出错处理即可较容易地进行文件编程。10.5程序设计举例

例10.6

若文件number.dat中存放了一组整数,试编程统计并输出文件中正整数、零和负整数的个数。

#include<stdio.h>

voidmain()

{

FILE*fp;

intp=0,n=0,z=0,temp;

fp=fopen(“number.dat”,“r”);

/*以只读方式打开文本文件*/

if(fp==NULL)

printf("filenotfound!\n");

else

{

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论