如果进行二进制I/O操作,那么我们更愿意一次读或写整个结构。因此,提供了下列两个函数以执行二进制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的基本问题是,它只能用于读在同一系统上已写的数据。多年之前,这并无问题(那时,所有的UNIX系统都运行于PDP-11上),而现在,很多异构系统通过网络相互连接起来,而且,这种情况已经非常普遍。常常有这种情形,在一个系统上写的数据,要在另一个系统上进行处理。在这种环境下,这两个函数可能就不能正常工作,其原因是:
(1)在一个结构中,同一成员的偏移量可能因编译器和系统而异(由于不同的对准要求)。确实,某些编译器有一个选项,选择它的不同值,或者使结构中的各成员紧密包装(这可以节省存储空间,而运行性能则可能有所下降);或者准确对齐(以便在运行时易于访问结构中的各成员)。这意味着即使在同一个系统上,一个结构的二进制存放方式也可能因编译器选项的不同而不同。
(2)用来存储多字节整数和浮点值的二进制格式在不同的机器体系结构间也可能不同。
在不同系统之间交换二进制数据的实际解决方法是使用较高级的协议(例如网络协议)。
本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/。