博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C Linux read write function extension
阅读量:5082 次
发布时间:2019-06-13

本文共 5165 字,大约阅读时间需要 17 分钟。

前言 - 赠送 readn / writen

  Linux 上默认的 read 和 write 函数会被信号软中断. 且 read 和 write 函数中第三个参数 count

#include 
extern ssize_t read(int fd, void * buf, size_t count);extern ssize_t write(int fd, const void * buf, size_t count);

也会因内部缓冲机制, 不一定保证读取或写入到指定 count 大小数据.

这里将 read 和 write 拓展成 readn 和 writen

//// readn - 力求读取 n 个字节// fd       : 文件描述符// buf      : 缓冲区// n        : 读取长度// return   : 返回读取的长度, -1 标识错误, < n 标识关闭, 默认 n//ssize_t readn(int fd, void * buf, size_t n) {    size_t div = n;    char * ptr = buf;    while (div > 0) {        ssize_t ret = read(fd, ptr, div);        if (ret < 0) {            if (errno == EINTR)                continue;            return -1;        }        if (ret == 0)             break;        ptr += ret;        div -= ret;    }    return n - div;}//// writen - 力求写入 n 个字节// fd       : 文件描述符// buf      : 缓冲区// n        : 读取长度// return   : 返回写入长度, -1 标识错误, 默认 n//ssize_t writen(int fd, const void * buf, size_t n) {    size_t div = n;    const char * ptr = buf;    while (div > 0) {        ssize_t ret = write(fd, ptr, div);        if (ret <= 0) {            if (errno == EINTR)                continue;            return -1;        }        ptr += ret;        div -= ret;    }    return n;}

有了这些收获, 不妨写个小测试

#include 
#include
#include
#include
//// readn - 力求读取 n 个字节// fd : 文件描述符// buf : 缓冲区// n : 读取长度// return : 返回读取的长度, -1 标识错误, < n 标识关闭, 默认 n//extern ssize_t readn(int fd, void * buf, size_t n);//// writen - 力求写入 n 个字节// fd : 文件描述符// buf : 缓冲区// n : 读取长度// return : 返回写入长度, -1 标识错误, 默认 n//extern ssize_t writen(int fd, const void * buf, size_t n);/* _oo0oo_ o8888888o 88" . "88 (| -_- |) 0\ = /0 ___/`---'\___ .' \\| |// '. / \\||| : |||// \ / _||||| -:- |||||- \ | | \\\ - /// | | | \_| ''\---/'' |_/ | \ .-\__ '-' ___/-. / ___'. .' /--.--\ `. .'___ ."" '< `.___\_<|>_/___.' >' "". | | : `- \`.;`\ _ /`;.`/ - ` : | | \ \ `_. \_ __\ /__ _/ .-` / / =====`-.____`.___ \_____/___.-`___.-'===== `=---=' */int main(int argc, char * argv[]) { ssize_t ret = writen(STDOUT_FILENO, "12345\n1", 6); printf("ret = %ld\n", ret); char buf[4]; ret = readn(STDIN_FILENO, buf, 3); buf[3] = '\0'; printf("ret = %ld, buf = %s\n", ret, buf); return 0;}

一忧一喜皆心火,一荣一枯皆眼尘,静心看透炎凉事,千古不做梦里人。

聪明人,一味向前看;智慧人,事事向后看;聪明人,是战胜别人的人;智慧人,是战胜自己的人。

修心当以净心为要,修道当以无我为基。

过去事,过去心,不可记得;现在事,现在心,随缘即可;未来事,未来心,不必劳心。

 

正文 -  缓冲读

  在了解 readn 套路基础上, 你是否有所想过那缓冲读写的实现思路呢. 这里不妨借用深入理解计算机系统

书中的思路实现一番.

struct rio {    int fd;             // 文件描述符    char * ptr;         // 下一次读取缓冲池 buf 起点    ssize_t cnt;        // 缓冲池 buf 字符数量    char buf[BUFSIZ];   // 缓冲池};// rio_init - rio 初始化inline void rio_init(struct rio * r, int fd) {    assert(r && fd >= 0);    r->fd = fd;    r->cnt = 0;    r->ptr = r->buf;}//// readn - 力求读取 n 个字节// r        : 缓冲读取对象// buf      : 缓冲区// n        : 读取长度// return   : 返回读取的长度, -1 标识错误, < n 标识关闭, 默认 n//extern ssize_t rio_readn(struct rio * r, void * buf, size_t n);//// rio_readline - 力求读取一行数据// r        : 缓冲读取对象// buf      : 缓冲区// n        : 读取长度// return   : 返回读取的长度, -1 标识错误, < n 标识关闭, 默认 n//extern ssize_t rio_readline(struct rio * r, void * buf, size_t n);

实现了缓冲读固定字符和缓冲读一行. 额外的缓冲写也是相似的思路, 简单点写不了会进入写缓冲区,

可以当课外作业自行实现.

// rio_read - 带缓冲版本的 readstatic ssize_t rio_read(struct rio * r, void * buf, size_t n) {    // 当缓冲区中没有数据, 我们重新填充缓冲区    while (r->cnt <= 0) {        r->cnt = read(r->fd, r->buf, sizeof r->buf);        if (r->cnt < 0) {            if (errno == EINTR)                continue;            return -1;        }        // EOF 直接返回        if (r->cnt == 0)            return 0;        // 重新设置 buffer ptr         r->ptr = r->buf;    }    // 尝试读取数据并返回    ssize_t cnt = r->cnt < n ? r->cnt : n;    memcpy(buf, r->ptr, cnt);    r->cnt -= cnt;    r->ptr += cnt;    return cnt;}//// readn - 力求读取 n 个字节// r        : 缓冲读取对象// buf      : 缓冲区// n        : 读取长度// return   : 返回读取的长度, -1 标识错误, < n 标识关闭, 默认 n//ssize_t rio_readn(struct rio * r, void * buf, size_t n) {    size_t div = n;    char * ptr = buf;    while (div > 0) {        ssize_t ret = rio_read(r, ptr, div);        if (ret < 0)            return -1;        if (ret == 0)             break;        ptr += ret;        div -= ret;    }    return n - div;    }//// rio_readline - 力求读取一行数据, 会吃掉最后一个 \n 字符// r        : 缓冲读取对象// buf      : 缓冲区// n        : 读取长度// return   : 返回读取的长度, -1 标识错误, < n 标识关闭, 默认 n//ssize_t rio_readline(struct rio * r, void * buf, size_t n) {    size_t i;    char * ptr = buf, c;    for (i = 1; i < n; ++i) {        ssize_t ret = rio_read(r, &c, 1);        if (ret < 0)            return -1;        if (c == '\n' || ret == 0)            break;        *ptr++ = c;    }    *ptr = '\0';    return i - 1;}

缓冲写实战包装要复杂一点. 和业务绑定重(或者实现多策略的). 例如缓冲区满了这时候的策略就由业务

决定, 是缓冲区扩容, 还是等待下次写事件触发. 等等, 真实战场的缓冲读写需要具体场景和机器打配合,

来构造满意的读写策略.

 

后记 -

转载于:https://www.cnblogs.com/life2refuel/p/10957979.html

你可能感兴趣的文章
用OGRE1.74搭建游戏框架(三)--加入人物控制和场景
查看>>
转化课-计算机基础及上网过程
查看>>
android dialog使用自定义布局 设置窗体大小位置
查看>>
ionic2+ 基础
查看>>
互联网模式下我们更加应该“专注”
查看>>
myeclipse集成jdk、tomcat8、maven、svn
查看>>
查询消除重复行
查看>>
Win 10 文件浏览器无法打开
查看>>
HDU 1212 Big Number(C++ 大数取模)(java 大数类运用)
查看>>
-bash: xx: command not found 在有yum源情况下处理
查看>>
[leetcode]Minimum Path Sum
查看>>
内存管理 浅析 内存管理/内存优化技巧
查看>>
hiho1079 线段树区间改动离散化
查看>>
【BZOJ 5222】[Lydsy2017省队十连测]怪题
查看>>
第二次作业
查看>>
【input】 失去焦点时 显示默认值 focus blur ★★★★★
查看>>
Java跟Javac,package与import
查看>>
day-12 python实现简单线性回归和多元线性回归算法
查看>>
Json格式的字符串转换为正常显示的日期格式
查看>>
[转]使用 Razor 进行递归操作
查看>>