代码开源(2)——UNIX 健壮I/O函数

来源:互联网 发布:金融的网络销售 编辑:程序博客网 时间:2024/06/05 17:38

       摘自《深入理解计算机系统》一书,几个IO读写的封装函数。一共是两类,一是无缓冲的输入输出函数;二是带缓冲的输入函数。这几个函数有一个共同点,就是比较好的处理了“不足值”的情况。所谓“不足值”是指read和write函数传送的字节比应用程序要求的要少。下面几种情况可能会出现不足值:(1)读时遇到EOF;(2)从终端读文本行;(3)读和写网络套接字,内部缓冲约束和较长的网络延迟会引起read和write返回不足值。

       这几个函数自动处理了上述提到的不足值,在像网络程序这样容易出现不足值的应用中,提供了方便、健壮和高效的I/O。

#ifndef RIO_H_#define RIO_H_#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <string.h>#define RIO_BUFSIZE 8192typedef struct{int rio_fd;int rio_cnt;char *rio_pbuf;char rio_buf[RIO_BUFSIZE];}rio_t;//无缓冲输入输出ssize_t rio_readn(int fd, void *usrbuf, size_t n);ssize_t rio_writen(int fd, void *usrbuf, size_t n);//带缓冲输入void rio_readinitb(rio_t *pr, int fd);ssize_t rio_read(rio_t *pr, char *usrbuf, size_t n);ssize_t rio_readnb(rio_t *pr, void *usrbuf, size_t n);ssize_t rio_readlineb(rio_t *pr, void *usrbuf, size_t maxlen);//无缓冲输入函数//成功返回输入的字节数,若EOF返回0,出错返回-1ssize_t rio_readn(int fd, void *usrbuf, size_t n){size_t nleft = n;ssize_t nread;char *pbuf = usrbuf;while(nleft > 0){//在某些系统中,当处理程序捕捉到一个信号时,被中断的慢系统调用(read, write, accept)//在信号处理程序返回时不再继续,而是立即返回给客户一个错误条件,并将errno设置成为EINTRif((nread = read(fd, pbuf, nleft)) < 0){if(errno == EINTR)nread = 0;    //中断造成的,再次调用readelsereturn -1;    //出错}else if(nread == 0)   //到了文件末尾break;nleft -= nread;pbuf += nread;}return n - nleft;}//无缓冲输出函数//成功返回输出的字节数,出错返回-1ssize_t rio_writen(int fd, void *usrbuf, size_t n){size_t nleft = n;ssize_t nwritten;char *pbuf = usrbuf;while(nleft > 0){//注意这里是小于等于,磁盘已满或超过一个给定进程的文件长度限制就出错了if((nwritten = write(fd, pbuf, nleft)) <= 0){if(errno == EINTR)nwritten = 0;elsereturn -1;}nleft -= nwritten;pbuf += nwritten;}return n; //注意与输入的区别,write不会返回不足值}//初始化rio_t结构void rio_readinitb(rio_t *pr, int fd){pr->rio_fd = fd;pr->rio_cnt = 0;pr->rio_pbuf = pr->rio_buf;}//带缓存函数 供内部调用ssize_t rio_read(rio_t *pr, char *usrbuf, size_t n){int cnt;while(pr->rio_cnt <= 0) //内部缓冲空了,进行重填{pr->rio_cnt = read(pr->rio_fd, pr->rio_buf, sizeof(pr->rio_buf)); //读到内部缓冲中if(pr->rio_cnt < 0) {if(errno != EINTR) //出错返回return -1;}else if(pr->rio_cnt == 0) //到文件末尾return 0;elsepr->rio_pbuf = pr->rio_buf; //重置指针位置}//从内部缓冲拷贝数据到用户缓冲中cnt = (pr->rio_cnt < n)? pr->rio_cnt: n; //取两者之间的小的memcpy(usrbuf, pr->rio_pbuf, cnt);pr->rio_pbuf += cnt;pr->rio_cnt -= cnt;return cnt;}//带缓冲输入函数ssize_t rio_readnb(rio_t *pr, void *usrbuf, size_t n){size_t nleft = n;ssize_t nread;char *pbuf = usrbuf;while(nleft > 0){//与无缓冲的区别在于这里调用的是rio_read而不是readif((nread = rio_read(pr, pbuf, nleft)) < 0){if(errno == EINTR)nread = 0;    //中断造成的,再次调用readelsereturn -1;    //出错}else if(nread == 0)   //到了文件末尾break;nleft -= nread;pbuf += nread;}return n - nleft;}//带缓冲输入函数,每次输入一行ssize_t rio_readlineb(rio_t *pr, void *usrbuf, size_t maxlen){int i, n;char c, *pbuf = usrbuf;for(i = 1; i < maxlen; i++){if((n = rio_read(pr, &c, 1)) == 1) //读一个字符{*pbuf++ = c;if(c == '\n') //读到换行符break;}else if(n == 0){if(i == 1) //空文件return 0;else       //读到了部分数据break;}else  //出错return -1;}*pbuf = 0; //添加字符串结束符return i;}#endif /* RIO_H_ */


原创粉丝点击