[Linux] RIO C++封裝

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);
}
相關文章
相關標籤/搜索