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");
}
  • 三种方法的结果:

  • 其他注意事项

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/89353973
今日推荐