RIO

CSAPP RIO包用于I/O

Posted on 2021-02-08,6 min read
RIO

- 解决short count

- 提供方便、健壮、高效的IO

两类函数

- 无缓冲的输入输出

  rio_readn

  rio_writen

​		绝不会返回不足值

- 带缓冲的输入输出

​        rio_readlineb

​            读文本行

​            停止条件

​                读了maxlen个字节

​                遇到了EOF

​                遇到了换行符

​        rio_readnb

​            读字节 不区分文本和二进制文件

​            停止条件

​           	 maxlen : 因为里面用了一个while循环,如果还有left,就继续读,如果buffer已经空了,就调用rio_read填充buffer后再读。

​            	遇到EOF

​        

​        readlineb和readnb可以混用,但不能和readn混用
/*my version of rio*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

typedef struct{
    int rio_fd; //file descriptor
    int rio_cnt; //unread bytes
    char rio_buffer[32];
    char *rio_p; //pointer to next unread byte;
} rio_t;

void rio_initb(rio_t *rp, int fd){
    rp->rio_fd = fd;
    rp->rio_cnt = 0;
    rp->rio_p = rp->rio_buffer;
}

//把buffer里的拷贝进usrbuf
int rio_read(rio_t *rp, char *usrbuf, size_t size){

    while(rp->rio_cnt <= 0){
        rp->rio_cnt = read(rp->rio_fd, rp->rio_buffer, sizeof(rp->rio_buffer));
        if(rp->rio_cnt < 0){
            if(errno != EINTR){
                return -1;
            }
        }else if(rp->rio_cnt == 0){
            return 0;
        }else{
            rp->rio_p = rp->rio_buffer;
        }
    }
    int cnt = size;
    if(cnt > rp->rio_cnt){
        cnt = rp->rio_cnt;
    }
    memcpy(usrbuf, rp->rio_p, cnt);
    rp->rio_p += cnt;
    rp->rio_cnt -= cnt;
    return cnt;
}

int rio_readnb(rio_t *rp, char *des, size_t size){
    int left = size;
    int n;
    char *p = des;
    while(left > 0){
        n = rio_read(rp, p, left);
        if(n < 0){
            return -1; /* errno set by read() */
        }else if(n==0){
            break; /* EOF */
        }else{
            left -= n;
            p += n;
        }
    }
    return (size - left);
}

int rio_readlineb(rio_t *rp, char* des, size_t max_size){
    int left = max_size-1;
    char *p = des;
    int n;
    while(left > 0){
        if(n = rio_read(rp, p, 1) == 1){
            left--;
            if(*p == '\n'){
                p++;
                break;
            }else{
                p++;
            }
            
        }else if(n==0){
            if(p == des) return 0; //no data read, EOF
            else break; // some data read, EOF
        }else{
            return -1;
        }
    }
    *p = 0;
    return p-des;
}

int main()
{
    rio_t rt;
    int fd1 = open("README2", O_RDONLY);
    rio_initb(&rt, fd1);

    
    char buf[64];
    int size = 64;
    rio_readlineb(&rt, buf, size);
    printf("%s", buf);

}

/****************************************
 * The Rio package - Robust I/O functions
 ****************************************/

/*
 * rio_readn - Robustly read n bytes (unbuffered)
 */
/* $begin rio_readn */
ssize_t rio_readn(int fd, void *usrbuf, size_t n)
{
    size_t nleft = n;
    ssize_t nread;
    char *bufp = usrbuf;

    while (nleft > 0)
    {
        if ((nread = read(fd, bufp, nleft)) < 0)
        {
            if (errno == EINTR) /* Interrupted by sig handler return */
                nread = 0;      /* and call read() again */
            else
                return -1; /* errno set by read() */
        }
        else if (nread == 0)
            break; /* EOF */
        nleft -= nread;
        bufp += nread;
    }
    return (n - nleft); /* Return >= 0 */
}
/* $end rio_readn */

/*
 * rio_writen - Robustly write n bytes (unbuffered)
 */
/* $begin rio_writen */
ssize_t rio_writen(int fd, void *usrbuf, size_t n)
{
    size_t nleft = n;
    ssize_t nwritten;
    char *bufp = usrbuf;

    while (nleft > 0)
    {
        if ((nwritten = write(fd, bufp, nleft)) <= 0)
        {
            if (errno == EINTR) /* Interrupted by sig handler return */
                nwritten = 0;   /* and call write() again */
            else
                return -1; /* errno set by write() */
        }
        nleft -= nwritten;
        bufp += nwritten;
    }
    return n;
}
/* $end rio_writen */

/* 
 * rio_read - This is a wrapper for the Unix read() function that
 *    transfers min(n, rio_cnt) bytes from an internal buffer to a user
 *    buffer, where n is the number of bytes requested by the user and
 *    rio_cnt is the number of unread bytes in the internal buffer. On
 *    entry, rio_read() refills the internal buffer via a call to
 *    read() if the internal buffer is empty.
 */
/* $begin rio_read */
static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)
{
    int cnt;

    while (rp->rio_cnt <= 0)
    { /* Refill 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) /* Interrupted by sig handler return */
                return -1;
        }
        else if (rp->rio_cnt == 0) /* EOF */
            return 0;
        else
            rp->rio_bufptr = rp->rio_buf; /* Reset buffer ptr */
    }

    /* Copy min(n, rp->rio_cnt) bytes from internal buf to user 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;
}
/* $end rio_read */

/*
 * rio_readinitb - Associate a descriptor with a read buffer and reset buffer
 */
/* $begin rio_readinitb */
void rio_readinitb(rio_t *rp, int fd)
{
    rp->rio_fd = fd;
    rp->rio_cnt = 0;
    rp->rio_bufptr = rp->rio_buf;
}
/* $end rio_readinitb */

/*
 * rio_readnb - Robustly read n bytes (buffered)
 */
/* $begin rio_readnb */
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)
{
    size_t nleft = n;
    ssize_t nread;
    char *bufp = usrbuf;

    while (nleft > 0)
    {
        if ((nread = rio_read(rp, bufp, nleft)) < 0)
            return -1; /* errno set by read() */
        else if (nread == 0)
            break; /* EOF */
        nleft -= nread;
        bufp += nread;
    }
    return (n - nleft); /* return >= 0 */
}
/* $end rio_readnb */

/* 
 * rio_readlineb - Robustly read a text line (buffered)
 */
/* $begin rio_readlineb */
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
{
    int n, rc;
    char c, *bufp = usrbuf;

    for (n = 1; n < maxlen; n++)
    {
        if ((rc = rio_read(rp, &c, 1)) == 1)
        {
            *bufp++ = c;
            if (c == '\n')
            {
                n++;
                break;
            }
        }
        else if (rc == 0)
        {
            if (n == 1)
                return 0; /* EOF, no data read */
            else
                break; /* EOF, some data was read */
        }
        else
            return -1; /* Error */
    }
    *bufp = 0;
    return n - 1;
}
/* $end rio_readlineb */

下一篇: ES使用过程中遇到的坑→