全部博文(842)
分类: 系统运维
2012-05-14 17:18:20
5.6节的函数一次操作一个字符,而5.7节的函数一次操作一行。如果我们执行二进制I/O,我们经常是想一次读写整个结构。为了使用getc或 putc,我们必须在整个结构里循环,一次一个字节,读写各个字节。我们不能使用一次一行函数,因为fputs当碰到空字节时结束写,而在结构里可能会有 空字节。类似的,fgets不能用来输入如果任何数据字节包含空字节或的换行符。因此,以下两个函数被用来执行二进制I/O。
这些函数有两种普遍的使用方法:
1、读写一个二进制数组。例如,写一个浮点数组的第2到第5人元素,我们可以写:
float data[10];
if (fwrite(&data[2], sizeof(float), 4, fp) != 4)
err_sys("fwrite error");
这里,我们指定size作为数组每个元素的尺寸而nobj作为元素的数量。
2、读写一个结构体。例如,我们可能这样写:
struct {
short count;
long total;
char name[NAMESIZE];
} item;
if (fwrite(&item, sizeof(item), 1, fp) != 1)
err_sys("fwrite error");
这里,我们指定size作为结构体的尺寸而nobj指定为1(写的对象的数量)。
这两种情况的明显的扩展是读写一个结构体数组。要这样做,size应该是结构体的sizeof,而nboj应该是数组的元素数量。
fread和fwrite都返回读入或写出的对象的数据。对于read,这个数量可以比nboj小,如果有错误发生或碰到文件结束。这些种情况下ferror和feof必须调用。对于write,如果返回值比所需的nobj少,表示发生错误。
二进制I/O的一个基本问题,是它只能用来读在同一系统上写的数据。这在很多年前,当所有UNIX系统都在PDP-11上时,是没问题的。但如今多种多样 的系统用网络连接在一起。想要在一个系统上写数据而在另一个上处理它是很普遍的。这两个函数将不能工作,基于两个原因:
1、一个结构体里的成员的偏移量在编译器间和系统间可以不同,因为不同的对齐需要。事实上,一些编译器有一个选项允许结构体被紧凑打包,以运行时的性能为
代价节省空间,或者精确地排列,来优化每个成员的运行访问时间。这意味着即使在同一个系统上,一个结构体的字节排列也可以不同,取决于编译器选项。
2、用来存储多字节整型和浮点型的值在各种机器架构上不同。
我们将在16章讨论套接字时碰到一些这样的问题。在不同系统上交换二进制数据的真实解决方案,是使用更高层的协议。我们将在8.14节回到fread函数,当我们用它来讯一个二进制结构体,UNIX进程记账记录的时候。