UNIX(编程-高级IO):08---非连续缓冲区读写函数(readv、writev)
一、函数功能
#include <sys/uio.h>
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
- 概念:readv和writev函数用于在一个函数调用中读、写多个非连续缓存。有时也将这两个函数称 为散布读(scatter read)和聚集写(gather write)
二、函数结构
- 参数1:描述符标志
- 参数2:指向于iovec结构体数组的指针
- 参数3:iovcnt指定iov数组中的元素数,其最大值受限于IOV_MAX(回忆图2-11)
struct iovec结构体:
struct iovec { void *iov_base; /* starting address of buffer */ size_t iov_len; /* size of buffer */ };
- writev函数从缓冲区中聚集输出数据的顺序是:iov[0]、iov[1]直至iov[iovcnt-1]
- writev返回:输出的字节总数,通常应等于所有的缓冲区长度之和。出错返回-1
- readv则将读入的数据按上述同样顺序散布到缓存中。 readv总是先填满一个缓存,然后再填写下一个
- readv返回:读得的总字节数。如果遇到文件结尾,已无数据可读,则返回0。出错返回1
三、writev的效率
我们需要完成一个功能:将两个缓冲区的内容连续写到一个文件中,有3中方法实现这个功:
- 下面是完成功能的函数:第二个缓冲区是调用者传递过来的一个参数,第一个缓冲区是我们自己创建的,它包含了第二个缓冲区的长度以及文件的其他信息的文件偏移量
static void _db_writeidx(DB *db, const char *key,off_t offset, int whence, off_t ptrval) { struct iovec iov[2]; char asciiptrlen[PTR_SZ + IDXLEN_SZ + 1]; int len; if ((db->ptrval = ptrval) < 0 || ptrval > PTR_MAX) err_quit("_db_writeidx: invalid ptr: %d", ptrval); sprintf(db->idxbuf, "%s%c%lld%c%ld\n", key, SEP,(long long)db->datoff, SEP, (long)db->datlen); len = strlen(db->idxbuf); if (len < IDXLEN_MIN || len > IDXLEN_MAX) err_dump("_db_writeidx: invalid length"); sprintf(asciiptrlen, "%*lld%*d", PTR_SZ, (long long)ptrval,IDXLEN_SZ, len); /* * If we’re appending, we have to lock before doing the lseek * and write to make the two an atomic operation. If we’re * overwriting an existing record, we don’t have to lock. */ if (whence == SEEK_END) /* we’re appending */ if (writew_lock(db->idxfd, ((db->nhash+1)*PTR_SZ)+1,SEEK_SET, 0) < 0) err_dump("_db_writeidx: writew_lock error"); /* * Position the index file and record the offset. */ if ((db->idxoff = lseek(db->idxfd, offset, whence)) == -1) err_dump("_db_writeidx: lseek error"); iov[0].iov_base = asciiptrlen; iov[0].iov_len = PTR_SZ + IDXLEN_SZ; iov[1].iov_base = db->idxbuf; iov[1].iov_len = len; if(writev(db->idxfd, &iov[0], 2) != PTR_SZ + IDXLEN_SZ + len) err_dump("_db_writeidx: writev error of index record"); if (whence == SEEK_END) if (un_lock(db->idxfd, ((db->nhash+1)*PTR_SZ)+1,SEEK_SET, 0) < 0) err_dump("_db_writeidx: un_lock error"); }
-
三种方法的结果:
- 其他注意事项