四个读写函数
一、readv和writev函数
功能:用于在一次函数调用中读写多个非连续缓冲区。有时也将这两个函数成为散布读(scatter read)和聚集写(gather write)。
#include <sys/uio.h>
ssize_t readv(int filedes, const struct iovec *iov , int iovcnt);
ssize_t writev(int filedes, const struct iovec*iov, int iovcnt);
Both return: number of bytes read or written, -1 on error
这两个参数的第二个参数是指向iovec结构的指针。
struct iovec {
void *iov_base; /* starting address of buffer */
size_t iov_len; /* size of buffer */
};
iov数组中的元素由iovcnt说明。其最大值受限于IOV_MAX。
writev以顺序iov[0],iov[1]至iov[iovcnt-1]从缓冲区中聚集输出数据。Writev返回输出的字节总数,通常它应等于所有缓冲区长度的总和。
readv则将读入的数据按上述同样的顺序散布到缓冲区中。readv总是先填满一个缓冲区,然后再填写下一个。readv返回读到的总字节数。如果遇到文件尾,已无数据可读,则返回0。
对于少量数据,使用writev/readv的固定开销大于得益。随着复制数据的增加,程序中复制缓冲区的开销也会增多。这时候,writev/readv这种替代方法就会有更大的吸引力。
二、readn和writen函数
功能:读写指定的N字节数据。
背景:
管道、FIFO以及某些设备,特别是终端、网络和STREAMS设备有下列两种性质:
1、 一次read操作所返回的数据可能少于所要求的数据,即使还没有达到文件尾端,也可能是这样。
2、 一次write操作的返回值也可能少于指定输出的字节数。
在读写磁盘文件时从未遇到过这样的情况,除非文件系统用完了空间,或者我们接近了配额限制,而不能将要求的数据全部写出。
#include "apue.h"
ssize_t readn(int filedes, void *buf, size_t nbytes);
ssize_t writen(int filedes, void *buf, size_t nbytes);
Both return: number of bytes read or written, -1 on error
在要将数据写到上面提到的文件类型上时,就可以用writen。但是只有当事先知道要接收的数量时,才可以使用readn(通常只调用read接收来自这些设备上的数据)。
示例:readn和writen函数的实现
#include "apue.h"
ssize_t /* Read "n" bytes from a descriptor */
readn(int fd, void *ptr, size_t n)
{
size_t nleft;
ssize_t nread;
nleft = n;
while (nleft > 0) {
if ((nread = read(fd, ptr, nleft)) < 0) {
if (nleft == n)
return(-1); /* error, return -1 */
else
break; /* error, return amount read so far */
} else if (nread == 0) {
break; /* EOF */
}
nleft -= nread;
ptr += nread;
}
return(n - nleft); /* return >= 0 */
}
ssize_t /* Write "n" bytes to a descriptor */
writen(int fd, const void *ptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
nleft = n;
while (nleft > 0) {
if ((nwritten = write(fd, ptr, nleft)) < 0) {
if (nleft == n)
return(-1); /* error, return -1 */
else
break; /* error, return amount written so far */
} else if (nwritten == 0) {
break;
}
nleft -= nwritten;
ptr += nwritten;
}
return(n - nleft); /* return >= 0 */
}