13.7 其他标准I/O函数
除了setvbuf(),其他函数均可在ANSI之前的实现中实现。
13.7.1 int ungetc( int c, FILE *fp )函数
int ungetc()函数把c指定的字符放回输入流中。如果把一个字符放入输入流中,下次调用标准输入函数时将读取该字符。ANSI C标准保证每次只会放回一个字符。如果实现允许把一行中的多个字符放回输入流,那么下一次输入函数读入的字符顺序与放回的顺序相反。
13.7.2 int fflush()函数
fflush()函数的原型如下:
int fflush( FILE *fp );
调用fflush()函数引起输入缓冲区中所有的未写入数据被发送到fp指定的输出文件。这个过程称为刷新缓冲区。如果fp是空指针,所有输出缓冲区都被刷新。在输入流中使用fflush()函数的效果是未定义的。只要最近一次操作不是输入操作,就可以用该函数来更新流(任何读写模式)。
13.7.3 int setvbuf()函数
setvbuf()函数的原型是:
int setvbuf( FILE *restrict fp, char *restrict buf, int mode, size_t size );
setvbuf()函数创建一个供标准I/O函数替换使用的缓冲区。在打开文件后且未对它进行其他操作之前,调用该函数。指针fp识别待处理的流,buf指向待使用的存储区。如果buf的值不是NULL,则必须创建一个缓冲区。然而,如果把NULL作为buf的值,该函数会为自己分配一个缓冲区。
变量size告诉setvbuf()数组的大小(size_t是一种派生的整数类型)。mode的选择如下:_IOFBF表示完全缓冲(在缓冲区满时刷新);_IOLBF表示行缓冲(在缓冲区满时或写入一个换行符时);_IONBF表示无缓冲。如果操作成功,函数返回0,否则返回一个非零值。
假设一个程序要存储一种数据对象,每个数据对象的大小是3000字节。可以使用setvbuf()函数创建一个缓冲区,其大小是该数据对象大小的整数倍。
13.7.4 二进制I/O:fread()和fwrite()
之前用到的标准I/O函数都是面向文本的,用于处理字符和字符串。如果在文件中保存数值数据?用fprintf()函数和%f转换说明只是把数值保存为字符串。例如,下面的代码:
double num = 1./3;
fprintf( fp, "%f", num );
把num存储为8个字符:0.333333。使用%.2f转换说明将其存储为4个字符:0.33。改变转换说明将改变存储该值所需的空间数量,也会导致存储不同的值。把num存储为0.33后,读取文件时就无法将其恢复为更高的精度。一般而言,fprintf()把数值转换为字符数据,这种转换可能会改变值。
为保证数值在存储前后一致,最精确的做法是使用与计算机相同的位组合来存储。因此,double类型的值应该存储在一个double大小的单元中。
如果以程序所用的表示法把数据存储在文件中,则称为二进制形式存储数据。不存在从数值形式到字符串的转换过程。对于标准I/O,fread()和fwrite()函数用于以二进制形式处理数据。
实际上,所有的数据都是以二进制形式存储的,甚至连字符都以字符码的二进制表示来存储。如果文件中的所有数据都被解释为字符码,则称该文件包含文本数据。如果部分或所有的数据都被解释为二进制形式的数值数据,则称该文件包含二进制数据(另外,用数据表示机器语言指定的文件都是二进制文件)。
二进制和文本的用法很容易混淆。ANSI C和许多操作系统都识别两种文件格式:二进制和文本。能以二进制数据或文本数据形式存储或读取信息。可以用二进制模式打开文件格式的文件,可以把文件存储在二进制形式的文件中。可以调用getc()拷贝包含二进制数据的文件。然而,一般而言,用二进制模式在二进制格式文件中存储二进制数据。类似地,最常用的还是以文本格式打开文本文件中的文本数据(通常文字处理器生成的文件都是二进制文件,因为这些文件中包含了大量非文本信息,如字体和格式等)。
13.7.5 size_t fwrite()函数
fwrite()函数的原型如下ÿ