readv(2) - Linux man page

名称

readv, writev, preadv, pwritev - 读取或写入多个缓冲区的数据

概要

#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);

ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,
               off_t offset);

ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt,
                off_t offset);
glibc 的功能测试宏要求(参见 feature_test_macros(7))
preadv(), pwritev(): _BSD_SOURCE

描述

readv() 系统调用从与文件描述符 fd 关联的文件中读取 iovcnt 个缓冲区,并将数据读入由 iov 描述的缓冲区中(“分散输入”)。

writev() 系统调用将由 iov 描述的 iovcnt 个缓冲区的数据写入与文件描述符 fd 关联的文件中(“集中输出”)。

指针 iov 指向一个 iovec 结构的数组,该结构在 <sys/uio.h> 中定义如下

struct iovec {
    void  *iov_base;    /* Starting address */
    size_t iov_len;     /* Number of bytes to transfer */
};
readv() 系统调用的工作方式与 read(2) 相同,只是会填充多个缓冲区。

writev() 系统调用的工作方式与 write(2) 相同,只是会写入多个缓冲区。

缓冲区按数组顺序处理。这意味着 readv() 会先完全填充 iov[0],然后才处理 iov[1],依此类推。(如果数据不足,则可能无法填充 iov 指向的所有缓冲区。) 同样,writev() 会先写入 iov[0] 的所有内容,然后才处理 iov[1],依此类推。

readv() 和 writev() 执行的数据传输是原子的:writev() 写入的数据作为一个单独的块写入,不会与其他进程中的写入输出混合(但请参阅 pipe(7) 以获取例外情况);类似地,readv() 保证从文件中读取一个连续的数据块,无论其他线程或进程执行的读取操作如何,这些线程或进程都具有引用相同打开文件描述符的文件描述符(请参阅 open(2))。

preadv() 和 pwritev()

preadv() 系统调用结合了 readv() 和 pread(2) 的功能。它执行与 readv() 相同的任务,但添加了第四个参数 offset,它指定要执行输入操作的文件偏移量。

pwritev() 系统调用结合了 writev() 和 pwrite(2) 的功能。它执行与 writev() 相同的任务,但添加了第四个参数 offset,它指定要执行输出操作的文件偏移量。

这些系统调用不会更改文件偏移量。与 fd 关联的文件必须能够进行寻址。

返回值

成功时,readv() 和 preadv() 返回读取的字节数;writev() 和 pwritev() 返回写入的字节数。发生错误时,返回 -1,并且 errno 会被设置为适当的值。

错误

错误与 read(2) 和 write(2) 中给出的错误相同。此外,preadv() 和 pwritev() 也可能由于与 lseek(2) 相同的原因而失败。 此外,定义了以下错误

EINVAL

iov_len 值的总和溢出了 ssize_t 值。或者,向量计数 iovcnt 小于零或大于允许的最大值。

版本

preadv() 和 pwritev() 首先出现在 Linux 2.6.30 中;库支持是在 glibc 2.10 中添加的。

符合

readv(), writev(): 4.4BSD (这些系统调用首次出现在 4.2BSD 中), POSIX.1-2001. Linux libc5 使用 size_t 作为 iovcnt 参数的类型,并使用 int 作为返回值类型。

preadv(), pwritev(): 非标准,但现代 BSD 系统中也存在。

说明

Linux 注意

POSIX.1-2001 允许实现对 iov 中传递的项目数量设置限制。实现可以通过在 <limits.h> 中定义 IOV_MAX,或者通过 sysconf(_SC_IOV_MAX) 的返回值来声明其限制。在 Linux 上,这些机制声明的限制是 1024,这正是内核的真实限制。但是,glibc 包装函数如果检测到底层内核系统调用失败是因为超过了这个限制,会执行一些额外的工作。对于 readv(),包装函数会分配一个足够大的临时缓冲区来容纳 iov 指定的所有项目,然后将该缓冲区传递给 read(2),将数据从缓冲区复制到 iov 元素的 iov_base 字段指定的位置,然后释放缓冲区。writev() 的包装函数使用临时缓冲区和对 write(2) 的调用执行类似的任务。

错误

不建议将对操作文件描述符的 readv() 或 writev() 调用与 stdio 库中的函数混合使用;结果将是不确定的,可能不是您想要的。

示例

以下代码示例演示了 writev() 的使用

char *str0 = "hello ";
char *str1 = "world\n";
struct iovec iov[2];
ssize_t nwritten;

iov[0].iov_base = str0;
iov[0].iov_len = strlen(str0);
iov[1].iov_base = str1;
iov[1].iov_len = strlen(str1);

nwritten = writev(STDOUT_FILENO, iov, 2);

参见

pread(2), read(2), write(2)

引用自

explain(1), explain(3), explain_readv(3), explain_readv_or_die(3), fio(1), process_vm_writev(2), pth(3), recv(2), signal(7), socket(7), spufs(2), spufs(7)