设为首页 加入收藏

TOP

C 标准I/O库粗略实现(二)
2018-10-21 18:11:01 】 浏览:255
Tags:标准 I/O 粗略 实现
_READ){ //判断文件是否可读 return EOF; } bufsize = f->flag & _UNBUF ? 1 : BUFSIZ; if(f->base == NULL){ //没有分配过缓冲区 if((f->base = (char *)malloc(bufsize)) == NULL){ return EOF; } } f->ptr = f->base; int n = read(f->fd,f->ptr,BUFSIZ); //系统调用read if(n == 0){ //到达文件结尾 f->base = NULL; f->cnt = 0; f-> flag |= _EOF; return EOF; }else if(n == -1){ //出错 f->cnt= 0; f->flag |= _ERR; return EOF; }else{ f->cnt = --n; return *f->ptr++; } }

_fillbuf的处理过程:

  • 判断文件是否可读
  • 判断调用read函数时应该读取的字节数,当文件设置了无缓冲时,读取1个字节,否则读取BUFSIZ个字节,BUFSIZ在<stdlib.h>中定义,定义了在该操作系统条件下缓冲区的最佳大小。
  • 判断是否分配过缓冲区(fopen不会分配缓冲区,会再第一次调用getc时分配)。
  • 调用系统函数read。
  • 判断read返回值,分为到达文件结尾、出错和正常读取三种情况。
  • 正常情况下返回缓冲区第一个字符给getc函数,并将cnt减1。

这里注意,到达文件结尾和出错都是返回EOF,区别是前者会将flag的_EOF位置1,后者会将flag的_ERR位置1,上游可以通过feofferror函数进行判断(这两个函数在上面已经实现过了)。

The character read is returned as an int value.
If the End-of-File is reached or a reading error happens, the function returns EOF and the corresponding error or eof indicator is set. You can use either ferror or feof to determine whether an error happened or the End-Of-File was reached.

_putc

int _putc(int x,FILE *f){
    return --f->cnt >= 0 ? *f->ptr++ = x : _flushbuf(x,f);
}

与_getc的实现相似,将写入的字符放到ptr指向的位置,并将ptr向后移动一位。当缓冲区满时,调用_flushbuf将缓冲区内容刷新到文件中。

_flushbuf

int _flushbuf(int x,FILE *f){

    if((f->flag & (_WRITE | _EOF | _ERR)) != _WRITE){     //判断文件是否可写
        return EOF;
    }

    int n;
    int bufsize = f->flag & _UNBUF ? 1 : BUFSIZ;
    if(f->base != NULL){
        n = write(f->fd,f->base,f->ptr - f->base);      //判断需要写入多少字节
        if(n != f->ptr - f->base){
            f->flag |= _ERR;
            return EOF;
        }
    }else{
        if((f->base = (char *)malloc(bufsize)) == NULL){
            f->flag |= _ERR;
            return EOF;
        }
    }

    if(x != EOF){
        f->cnt = bufsize - 1;
        f->ptr = f->base;
        *f->ptr++ = x;
    }else{          //当写入EOF时,代表强制刷新缓冲区内容到文件中
        f->cnt = bufsize;
        f->ptr = f->base;
    }
    return x;
}

_flushbuf的处理过程:

  • 判断文件是否可写。
  • 当已分配过缓冲区时,将缓冲区的内容通过系统调用write写入文件中。
  • 当没有分配过缓冲区时,分配缓冲区。
  • 判断当写入的字符为EOF时,说明调用此函数的目的为强制刷新缓冲区,不写入字符。将cnt赋值为BUFSIZ,ptr赋值为缓冲区首地址base。
  • 当写入字符不为EOF时,说明缓冲区已满,需要将缓冲区刷新到文件中。cnt为BUFSIZE - 1,将写入的字符x放到到缓冲区的第一格,然后将ptr向后移动一个char单位。

注意,调用write函数时,写入的字节数不能写死为1或者BUFSIZ:

n = write(f->fd,f->base,f->ptr - f->base);      //判断需要写入多少字节

image

如上图,我们需要写入base至ptr之间的数据,而不是BUFSIZ,因为我们可能会强制刷新缓冲区而不是等到缓冲区满了才刷新缓冲区。

还有一点:当我们想要强制刷新缓冲区时,第一个参数x该传入什么呢?K&R传递的是字符0,但是我认为这样会污染缓冲区,所以我的实现是传入一个特殊字符EOF,根据EOF来做不同的处理:

if(x != EOF){
    f->cnt = bufsize - 1;
    f->ptr = f->base;
    *f->ptr++ = x;
}else{          //当写入EOF时,代表强制刷新缓冲区内容到文件中
    f->cnt = bufsize;
    f->ptr = f->base;
}

当缓冲区满时,刷新缓冲区后缓冲区的表现:
image
当强制刷新缓冲区时,缓冲区的表现:
image
但是按照K&R的方式来强制刷新缓冲区时,缓冲区的表现:
image

这样会污染缓冲区,所以我的实现是传入EOF来强制刷新缓冲区。

_fflush
_fflush(FILE *f)的作用是把缓冲区内容写入文件。当参数为空时,会刷新所有文件:

int _fflush(FILE *f){

        int res = 0;
    if(f == NULL){
        for(int i = 0; i < OPEN_MAX; i++){          //当参数为NULL时,刷新所有的文件流
                       if((f->flag & _WRITE) && (_fflush(&_iob[i]) == -1)){  //有一个出错即返回-1
                           res = EOF;
                       }
        }
        }else{
            if(f->flag & _WRITE){
                    _flushbuf(EOF,f);
            }else{
                res = EOF;
            }
        }

    if(f->flag & _ERR){     //出错
                res = EOF;
    }
        return res;
}

_fflush的处理过程:

  • 判断参数是否为空,如果为空的话,遍历_iob数组,将所有文件流都强制刷新。
  • 如果参数不为空,判断文件是否可写,再调用_flushbuf进行刷新,注意此处传递给_flushbuf的参数是EOF。还有一点就是判断_flushbuf是否出错不是判断返回值是否为-1,因为参数为EOF时的返回值也为-1,所以此处用flag &am
首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇十六进制带小数转换成十进制 下一篇关于C语言中static保留字的使用

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目