一旦打开了流,则可在三种不同类型的非格式化I/O中进行选择,对其进行读、写操作:
(1)每次一个字符的I/O。一次读或写一个字符,如果流是带缓冲的,则标准I/O会处理所有缓冲。
(2)每次一行的I/O。如果想要一次读或写一行,则使用fgets和fputs。每行都以一个换行符终止。当调用fgets时,应说明能处理的最大行长。
(3)直接I/O。fread和fwrite函数支持这种类型的I/O。每次I/O操作读或写某种数量的对象,而每个对象具有指定的长度。这两个函数常用于从二进制文件中每次读或写一个结构。
直接I/O(direct I/O)这个术语来自ISO C标准,有时也被称为二进制I/O、一次一个对象I/O、面向记录的I/O或面向结构的I/O。
1、输入函数
以下三个函数可用于一次读一个字符。
#include <stdio.h> int getc( FILE *fp ); int fgetc( FILE *fp ); int getchar( void ); 三个函数的返回值:若成功则返回下一个字符,若已到达文件结尾或出错则返回EOF
函数getchar等价于getc(stdin)。前两个函数的区别是getc可被实现为宏,而fgetc则不能实现为宏。这意味着:
(1)getc的参数不应当是具有副作用的表达式。
(2)因为fgetc一定是一个函数,所以可以得到其地址。这就允许将fgetc的地址作为一个参数传送给另一个函数。
(3)调用fgetc所需时间很可能长于调用getc,因为调用函数通常所需的时间长于调用宏。
这三个函数在返回下一个字符时,会将其unsigned char类型转换为int类型。说明为不带符号的理由是,如果最高位为1也不会使返回值为负。要求整型返回值的理由是,这样就可以返回所有可能的字符再加上一个已出错或已到达文件尾端的指示值。在<stdio.h>中的常量EOF被要求是一个负值,其值经常是-1。这就意味着不能将这三个函数的返回值存放在一个字符变量中,以后还要将这些函数的返回值与常量EOF相比较。
注意,不管是出错还是到达文件尾端,这三个函数都返回同样的值。为了区分这两种不同的情况,必须调用ferror或feof。
#include <stdio.h> int ferror( FILE *fp ); int feof( FILE *fp ); 两个函数返回值:若条件为真则返回非0值(真),否则返回0(假) void clearerr( FILE *fp );
在大多数实现中,为每个流在FILE对象中维持了两个标志:
- 出错标志。
- 文件结束标志。
调用clearerr则清除这两个标志。
从流中读取数据以后,可以调用ungetc将字符再压送回流中。
#include <stdio.h> int ungetc( int c, FILE *fp ); 返回值:若成功则返回c,若出错则返回EOF
压送回流中的字符以后又可从流中读出,但读出的字符的顺序与压送回的顺序相反。应当了解,虽然ISO C允许实现支持任意次数的回送,但是它要求实现提供一次只送回一个字符。我们不能期望一次能送回多个字符。
回送的字符不必一定是上一次读到的字符。不能回送EOF,但是当已经达到文件尾端时,仍可以回送一个字符,下次读将返回该字符,再次读则返回EOF。之所以能这样做的原因是一次成功的ungetc调用会清除该流的文件结束标志。???(这原因解释的,越解释越糊涂)
当正在读一个输入流,并进行某种形式的分字或分记号操作时,会经常用到回送字符操作。有时需要先看一看下一个字符,以决定如何处理当前字符。然后就需要方便地将刚查看的字符送回,以便下一次调用getc时返回该字符。如果标准I/O库不提供回送能力,就需要将该字符存放到一个我们自己的变量中,并设置一个标志以便判别在下一次需要一个字符时是调用getc,还是从我们自己的变量中取用。
用ungetc压送回字符时,并没有将它们写到文件中或设备上,只是将它们写回标准I/O库的流缓冲区中。
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,staout),putc可实现为宏,而fputc则不能实现为宏。
本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/。