RIO包是CSAPP中一個基於read和write函數實現的可以處理終端並提供了帶緩衝區讀取的IO包。代碼很簡單,但很巧妙。
縮減了原程序的初始化等函數以後,主要有如下四個對外函數:函數
1.ssize_t readn(int fd,void *usrbuf,size_t n);
fd爲經過open獲得的文件描述符,一般爲一個小整數。該函數從指定文件讀取n個byte到usrbuf中。若是成功執行,返回傳輸的字節數,若是讀到EOF,返回0,若是出錯,返回-1。this
2.ssize_t writen(int fd,void *usrbuf,size_t n);
該函數將usebuf中最多n個字節寫到文件中。若是成功,返回寫入的字節數,若是出錯返回-1.code
3.ssize_t readlineb(rio_t rp,void usrbuf,size_t maxlen);
rio_t是一個定義樂緩衝區的結構體,具體實現見下面代碼。該函數一次從緩衝區/文件讀取一行數據(最長不超過maxlen)
4.ssize_t readnb(rio_t rp,void usrbuf,size_t n);
該函數是帶有緩衝區版本的read,相似於readn。
myrio.hstring
#pragma once #include <unistd.h> #include <sys/types.h> #include <fcntl.h> #include <errno.h> #include <sys/stat.h> #include <cstring> //a buffer named rio_t #define RIO_BUFSIZE 8192 typedef struct rio_t{ int rio_fd; int rio_cnt; //unread bytes in rio_buf char *rio_bufptr; //next unread byte in rio_buf char rio_buf[RIO_BUFSIZE]; //internal buffer rio_t(int fd) :rio_fd(fd),rio_cnt(0),rio_bufptr(rio_buf){ } } rio_t; class Rio{ public: //io function without internal buffer //Succeed: return the number of byte; EOF: return 0; Fail: return -1 ssize_t readn(int fd,void *usrbuf,size_t n); ssize_t writen(int fd,void *usrbuf,size_t n); //io function with internal buffer //Succeed: return the number of byte; EOF: return 0; Fail: return -1 ssize_t readlineb(rio_t *rp,void *usrbuf,size_t maxlen); ssize_t readnb(rio_t *rp,void *usrbuf,size_t n); private: //read with buffer ssize_t rio_read(rio_t *rp,char *usrbuf,size_t n); };
myrio.cppit
#include "myrio.h" //the difference between these function and system's is that: //this function can deal with the interrupt. ssize_t Rio::readn(int fd,void *usrbuf,size_t n){ size_t nleft = n; ssize_t nread; char *buf = static_cast<char*>(usrbuf); while(nleft > 0){ if((nread = read(fd,buf,nleft))<0){ if(errno ==EINTR) nread = 0; else return -1; }else if(nleft == 0){ break; }else{ nleft -= nread; buf += nread; } } return (n - nleft); } ssize_t Rio::writen(int fd,void *usrbuf,size_t n){ size_t nleft = n; ssize_t nwriten; char *buf = static_cast<char*>(usrbuf); while(nleft > 0){ if((nwriten = write(fd,buf,nleft)) <= 0){ if(errno == EINTR) nwriten = 0; else return -1; }else{ nleft -= nwriten; buf += nwriten; } return n; } } ssize_t Rio::rio_read(rio_t *rp,char *usrbuf,size_t n){ int cnt; while(rp->rio_cnt <= 0){ //refill rio_buf if buf is empty rp->rio_cnt = read(rp->rio_fd,rp->rio_buf,sizeof(rp->rio_buf)); if(rp->rio_cnt < 0){ if(errno != EINTR) return -1; }else if(rp->rio_cnt == 0){ return 0; }else{ rp->rio_bufptr = rp->rio_buf; } } cnt = n; if(rp->rio_cnt < n) cnt = rp->rio_cnt; memcpy(usrbuf,rp->rio_bufptr,cnt); rp->rio_bufptr += cnt; rp->rio_cnt -= cnt; return cnt; } ssize_t Rio::readlineb(rio_t *rp,void *usrbuf,size_t maxlen){ char c; char *buf = static_cast<char*>(usrbuf); int n,rc; for(n=1;n<maxlen;n++){ if((rc = rio_read(rp,&c,1)) == 1){ *buf = c; buf++; if(c == '\n') break; }else if(rc == 0){ if(n == 1) return 0; else break; }else{ return -1; } } *buf = '\0'; return n; } ssize_t Rio::readnb(rio_t *rp,void *usrbuf,size_t n){ size_t nleft = n; ssize_t nread; char *buf = static_cast<char*>(usrbuf); while(nleft > 0){ if((nread = rio_read(rp,buf,nleft)) < 0){ if(errno == EINTR) nread = 0; else return -1; }else if(nread == 0){ break; }else{ nleft -= nread; buf += nread; } } return (n-nleft); }