5.6 读和写流
5.6 读和写流
一旦打开了流,则可在三种不同类型的非格式化I/O中进行选择,对其进行读、写操作。
(1) 每次一个字符的I / O。一次读或写一个字符,如果流是带缓存的,则标准I / O函数处理所有缓存。
(2) 每次一行的I / O。使用fgets和fputs一次读或写一行。每行都以一个新行符终止。当调用fgets时,应说明能处理的最大行长。
(3) 直接I / O。fread和fwrite函数支持这种类型的I / O。每次I / O操作读或写某种数量的对象,而每个对象具有指定的长度。这两个函数常用于从二进制文件中读或写一个结构。
5.6.1 输入函数
以下三个函数可用于一次读一个字符:
#include<stdio.h>
int getc( FILE* fp);
int fgetc(FILE*fp);
int getchar( void); //equal to getc(stdin);
前两个函数的区别在于getc可被实现为宏,而fgetc则不能实现为宏。这意味着:
(1) getc的参数不应当是具有副作用的表达式。
(2) 因为fgetc一定是个函数,所以可以得到其地址。这就允许将fgetc的地址作为一个参数传送给另一个函数。
(3) 调用fgetc所需时间很可能长于调用getc,因为调用函数通常所需的时间长于调用宏。检验一下<stdio.h>头文件的大多数实现,从中可见getc是一个宏,其编码具有较高的工作效率。
这三个函数以unsigned char 类型转换为int的方式返回下一个字符。说明为不带符号的理由是,如果最高位为1也不会使返回值为负。要求整型返回值的理由是,这样就可以返回所有可能的字符值再加上一个已发生错误或已到达文件尾端的指示值。在<stdio.h>中的常数EOF被要求是一个负值,其值经常是-1。这就意味着不能将这三个函数的返回值存放在一个字符变量中,以后还要将这些函数的返回值与常数EOF相比较。
注意,不管是出错还是到达文件尾端,这三个函数都返回同样的值。为了区分这两种不同的情况,必须调用ferror或feof。
#include<stdio.h>
int ferror( FILE*fp);
int feof( FILE*fp);
void clearerr( FILE*fp);
前两个函数返回值:若条件为真,则返回非0值;否则返回0。
在大多数实现的FILE对象中,为每个流保持了两个标志:
l 出错标志。
l 文件结束标志。
调用clearerr则清除这两个标志。
从一个流读之后,可以调用ungetc将字符再送回流中。
#include<stdio.h>
int ungetc( int c, FILE*fp);
成功则返回c,失败则返回EOF;
送回到流中的字符以后又可从流中读出,但读出字符的顺序与送回的顺序相反。应当了解,虽然ANSI C允许支持任何数量的字符回送的实现,但是它要求任何一种实现都要支持一个字符的回送功能。
回送的字符,不一定必须是上一次读到的字符。EOF不能回送。但是当已经到达文件尾端时,仍可以回送一字符。下次读将返回该字符,再次读则返回EOF。之所以能这样做的原因是一次成功的ungetc调用会清除该流的文件结束指示。
当正在读一个输入流,并进行某种形式的分字或分记号操作时,会经常用到回送字符操作。有时需要先看一看下一个字符,以决定如何处理当前字符。然后就需要方便地将刚查看的字符送回,以便下一次调用getc时返回该字符。如果标准I / O库不提供回送能力,就需将该字符存放到一个我们自己的变量中,并设置一个标志以便判别在下一次需要一个字符时是调用getc,还是从我们自己的变量中取用。
5.6.2 输出函数
对应于上面所述的每个输入函数都有一个输出函数。
#include <stdio.h>
int putc(int c, FILE*fp);
int fputc(int c,FILE*fp);
int putchar(int c);
三个函数返回值:成功返回c;失败返回EOF.
与输入函数一样,putchar(c) 等同于putc(c, stdout),putc 可被实现为宏,而fputc 则不能实现为宏。