5.8 二进制I/O
5.8 二进制I/O
上面所述函数以一次一个字符或一次一行的方式进行操作。如果为二进制I/O,那么我们更愿意一次读或写整个结构。为了使用getc或putc做到这一点,必须循环通过整个结构,一次读或写一个字节,麻烦且费时。若使用fputs,它在遇到null字节时就停止,而在结构中可能含有null字节,所以不能使用每次一行函数实现这种要求。相类似,如果输入数据中包含有null字节或新行符,则fgets也不能正确工作。因此,提供了下列两个函数以执行二进制I / O操作
#include <stdio.h>
size_t fread(void*restrict ptr, size_t size, size_t nobj,FILE*restrict fp);
size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE*restrict fp);
两个函数的返回值为读或写的对象数。
常见的用法有两种,如下:
(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,nobj应是该数组中的元素数。
fread和fwrite返回读或写的对象数。对于读,如果出错或到达文件尾端,则此数字可以少于nobj。在这种情况,应调用ferror或feof以判断究竟是那一种情况。对于写,如果返回值少于所要求的nobj,则出错。
使用二进制I / O的基本问题是,它只能用于读已写在同一系统上的数据。现在,很多异构系统通过网络相互连接起来。常常有这种情形,在一个系统上写的数据,在另一个系统上处理。在这种环境下,这两个函数可能就不能正常工作,其原因是:
(1) 在一个结构中,同一成员的位移量可能随编译程序和系统的不同而异(由于不同的对准要求)。确实,某些编译程序有一选择项,它允许紧密包装结构(节省存储空间,而运行性能则可能有所下降);或准确对齐,以便在运行时易于存取结构中的各成员。这意味着即使在单一系统上,一个结构的二进制存放方式也可能因编译程序的选择项而不同。
(2) 用来存储多字节整数和浮点值的二进制格式在不同的系统结构间也可能不同。
在不同系统之间交换二进制数据的实际解决方法是使用较高层次的协议。