C语言读写文件函数:read/write,pread/pwrite,readv/writev,preadv/pwritev,preadv2/pwritev2

函数原型

// 最基本的read,write函数,读写一个buffer的数据
// read, write - read from or write to a file descriptor
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

// 在read,write函数基础上,可指定位置偏移量,从fd指定的文件offset处进行读写
// pread, pwrite - read from or write to a file descriptor at a given offset
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);

// readv,writev系列函数,可一次性读写多个不连续的buffer,把buffer数组中的内容写入到文件或者从一个文件读取内容到buffer数组
// 注意第二个参数是struct iovec指针,可以传入指针或数组。每个struct iovec都是一段固定长度的buffer。
// 这些函数定义在头文件<sys/uio.h>中
// readv, writev, preadv, pwritev, preadv2, pwritev2 - read or write data into multiple buffers
#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基础上,增加了指定位置偏移量的参数
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);
// 在preadv/pwritev基础上,增加了flag,如RWF_DSYNC, RWF_SYNC, RWF_HIPRI, RWF_NOWAIT, RWF_APPEND等,
// 控制读写时同步、优先级等行为
ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);

// struct iovec定义,起始地址和长度
struct iovec {
    void  *iov_base;    /* Starting address */
    size_t iov_len;     /* Number of bytes to transfer */
};

示例程序

read/write/pread/pwrite函数比较直观,这里仅示例readv/writev函数用法。
把程序中定义的buf通过writev函数输出到屏幕上。

#include <sys/uio.h>
#include <string.h>
#include <unistd.h>

int main() {

    char* buf1 = "hello ";
    char* buf2 = "world\n";

    struct iovec vec[2];				// iovec数组,输出buf

    vec[0].iov_base = buf1;				// 赋值方式1
    vec[0].iov_len = strlen(buf1);
//    vec[1].iov_base = buf2;
//    vec[1].iov_len = strlen(buf2);
    vec[1] = {							// 赋值方式2
            .iov_base = buf2,
            .iov_len = strlen(buf2)
    };

    writev(STDOUT_FILENO, vec, 2);		// writev输出到指定文件,这里是标准输出


    char* buf3 = "Hi ";
    char* buf4 = "barbie!\n";
    struct iovec *pv;					// 使用iovec指针
    pv = new iovec[] {					// 为iovec指针赋值
            {.iov_base = buf3, .iov_len = strlen(buf3)},
            {.iov_base = buf4, .iov_len = strlen(buf4)},
    };
    writev(STDOUT_FILENO, pv, 2);		// 把iovec指针指向的buf内容输出到stdout

    return 0;
}

分析

读写多个缓冲区,有几种策略:

  1. 调用read、write分别操作多次
    这种方式多次切换内核态,效率最低。

  2. 把多个缓冲区复制合并到同一个大的缓冲区中,一次read、write操作
    调用一次系统调用,切换一次内核态,调用开销低。
    效率主要取决于复制操作,当数据量比较小,复制开销不大时,效率和readv/writev接近。

  3. 调用readv、writev一次性操作多个缓冲区
    系统调用一次,开销低。
    当多块缓冲区数据较多,赋值开销增大时,这种方式比上述第二种方法更高效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

抓饼先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值