C语言文件读写操作中缓冲区问题和setbuf函数详解

清除和设置文件缓冲区
(1).清除文件缓冲区函数: int fflush(FILE *stream); int flushall(); fflush()函数将清除由stream指向的文件缓冲区里的内容,常用于写完一些数据后,立即用该函数清除缓冲区,以免误操作时,破坏原来的数据。 flushall()将清除所有打开文件所对应的文件缓冲区。

(2).设置文件缓冲区函数 void setbuf(FILE *stream,char *buf); void setvbuf(FILE *stream,char *buf,int type,unsigned size); 这两个函数将使得打开文件后,用户可建立自己的文件缓冲区,而不使用fopen()函数打开文件设定的默认缓冲区。 对于setbuf()函数,buf指出的缓冲区长度由头文件stdio.h中定义的宏BUFSIZE的值决定,缺省值为512字节。当选定buf为空时,setbuf函数将使的文件I/O不带缓冲。而对setvbuf函数,则由malloc函数来分配缓冲区。参数size指明了缓冲区的长度(必须大于0),而参数type则表示了缓冲的类型,其值可以取如下值: type 值 含义 _IOFBF 文件全部缓冲,即缓冲区装满后,才能对文件读写 _IOLBF 文件行缓冲,即缓冲区接收到一个换行符时,才能对文件读写 _IONBF 文件不缓冲,此时忽略buf,size的值,直接读写文件,不再经过文件缓冲区缓冲

 

文件的随机读写函数

前面介绍的文件的字符/字符串读写,均是进行文件的顺序读写,即总是从文件的开头开始进行读写。这显然不能满足我们的要求,C语言提供了移动文件指针和随机读写的函数,它们是:

(1).移动文件指针函数: long ftell(FILE *stream); int rewind(FILE *stream); fseek(FILE *stream,long offset,int origin); 函数ftell()用来得到文件指针离文件开头的偏移量。当返回值是-1时表示出错。rewind()函数用于文件指针移到文件的开头,当移动成功时,返回0,否则返回一个非0值。fseek()函数用于把文件指针以origin为起点移动offset个字节,其中origin指出的位置可有以下几种: origin 数值 代表的具体位置 SEEK_SET 0 文件开头 SEEK_CUR 1 文件指针当前位置 SEEK_END 2 文件尾 例如: fseek(fp,10L,0); 把文件指针从文件开头移到第10字节处,由于offset参数要求是长整型数,故其数后带L。 fseek(fp,-15L,2); 把文件指针从文件尾向前移动15字节。

(2).文件随机读写函数int fread(void *ptr,int size,int nitems,FILE *stream); int fwrite(void *ptr,int size,int nitems,FILE *stream); fread()函数从流指针指定的文件中读取nitems个数据项,每个数据项的长度为size个字节,读取的nitems数据项存入由ptr指针指向的内存缓冲区中,在执行fread()函数时,文件指针随着读取的字节数而向后移动,最后移动结束的位置等于实际读出的字节数。该函数执行结束后,将返回实际读出的数据项数,这个数据项数不一定等于设置的nitems,因为若文件中没有足够的数据项,或读中间出错,都会导致返回的数据项数少于设置的nitems。当返回数不等于nitems时,可以用feof()或ferror()函数进行检查。 fwrite()函数从ptr指向的缓冲区中取出长度为size字节的nitems个数据项,写入到流指针stream指向的文件中,执行该操作后,文件指针将向后移动,移动的字节数等于写入文件的字节数目。该函数操作完成后,也将返回写入的数据项数。

 

setbuf函数 详解

程序输出有两种方式:一种是即时处理方式,另一种是先暂存起来,然后再大块写入的方式,前者往往造成较高的系统负担。因此,c语言实现通常都允许程序员进行实际的写操作之前控制产生的输出数据量。

这种控制能力一般是通过库函数setbuf实现的。如果buf是一个大小适当的字符数组,那么:

setbuf(stdout,buf);

语句将通知输入/输出库,所有写入到stdout的输出都应该使用buf作为输出缓冲区,直到buf缓冲区被填满或者程序员直接调用fflush(译注:对于由写操作打开的文件,调用fflush将导致输出缓冲区的内容被实际地写入该文件),buf缓冲区中的内容才实际写入到stdout中。缓冲区的大小由系统头文件<stdio.h>中的BUFSIZ定义。

下面的程序的作用是把标准输入的内容复制到标准输出中,演示了setbuf库函数最显而易见的用法:

#include <stdio.h>

main()

{

int c;

char buf[BUFSIZ];

setbuf(stdout, buf);

    while((c=getchar())!=EOF)

        putchar(c);

}

    遗憾的是,这个程序是错误的,仅仅是因为一个细微的原因。程序中对库函数setbuf的调用,通知了输入/输出库所有字符的标准输出应该首先缓存在buf中。要找到问题出自何处,我们不妨思考一下buf缓冲区最后一次被清空是在什么时候?答案是在main函数结束之后,作为程序交回控制给操作系统之前C运行时库所必须进行的清理工作的一部分。但是,在此之前buf字符数组已经被释放!

    要避免这种类型的错误有两种办法。第一种办法是让缓冲数组成为静态数组,既可以直接显式声明buf为静态:

static char buf[BUFSIZ];

也可以把buf声明完全移到main函数之外。第二种办法是动态分配缓冲区,在程序中并不主动释放分配的缓冲区(译注:山于缓冲区是动态分配的,所以main函数结束时并不会释放该缓冲区,这样C运行时库进行清理工作时就不会发生缓冲区已释放的情况):

char *malloc();

setbuf(stdout,malloc(BUFSIZ));

    如果读者关心一些编程“小技巧”,也许会注意到这里其实并不需要检查malloc函数调用是否成功。如果malloc函数调用失败,将返回一个null指针。setbuf函数的第二个参数取值可以为null,此时标准输出不需要进行缓冲。这种情况下,程序仍然能够工作,只不过速度较慢而已。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值