T9的空间

You will never walk alone!

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  69 随笔 :: 0 文章 :: 28 评论 :: 0 Trackbacks
这一章会让你想起一些尘封的记忆
上大学的时候,教C语言的老师会教大家文件IO,那个时候讲的都是标准输入输出,都是C库的实现,和第三章Unbuffered IO要区别开来,目的之前讲过
减少System Call的调用次数,提高Performance
Java上也有类似的实现,只不过Java的实现会更加Common一些,类似BufferedInputStream/BufferedOutputStream,介质则分为很多种,例如FileInputStream
Android Bionic C Lib跟其他C Lib一样样子都是类似 FILE* 里面会封装上管理流所需要的信息: 真正IO操作的file descriptor;缓冲区指针和大小...

对于缓冲一般
stderr是不带缓冲的
如果是终端设备则是行缓冲,否则是全缓冲
然后这里会顺带提到freopen,这个东西会让你想到你启蒙的时光,略表想念,读了一下Bionic 中 freopen的实现贴在下面
#include <sys/types.h>
#include 
<sys/stat.h>
#include 
<fcntl.h>
#include 
<errno.h>
#include 
<unistd.h>
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
"local.h"

/*
 * Re-direct an existing, open (probably) file to some other file.
 * ANSI is written such that the original file gets closed if at
 * all possible, no matter what.
 
*/

FILE 
*
freopen(
const char *file, const char *mode, FILE *fp)
{
    
int f;
    
int flags, isopen, oflags, sverrno, wantfd;

    
if ((flags = __sflags(mode, &oflags)) == 0{
        
//做(r,w,+)到(O_RDONLY,O_WRONLY,O_RDWR,O_TRUNC)的转换.
        (void) fclose(fp);
        
return (NULL);
    }


    
if (!__sdidinit)
        __sinit();

    FLOCKFILE(fp);

    
/*
     * There are actually programs that depend on being able to "freopen"
     * descriptors that weren't originally open.  Keep this from breaking.
     * Remember whether the stream was open to begin with, and which file
     * descriptor (if any) was associated with it.  If it was attached to
     * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
     * should work.  This is unnecessary if it was not a Unix file.
     
*/

    
if (fp->_flags == 0{
        fp
->_flags = __SEOF;    /* hold on to it */
        isopen 
= 0;
        wantfd 
= -1;
    }
 else {
        
/* flush the stream; ANSI doesn't require this. */
        
if (fp->_flags & __SWR)
            (
void) __sflush(fp);
        
/* if close is NULL, closing is a no-op, hence pointless */
        isopen 
= fp->_close != NULL;
        
if ((wantfd = fp->_file) < 0 && isopen) {
            (
void) (*fp->_close)(fp->_cookie);
            isopen 
= 0;
        }

    }

    
//对fp做一些clean的动作

    
/* Get a new descriptor to refer to the new file. */
    f 
= open(file, oflags, DEFFILEMODE);
    
//DEFFILEMODE默认为RWRWRW
    
    
if (f < 0 && isopen) {
        
/* If out of fd's close the old one and try again. */
        
if (errno == ENFILE || errno == EMFILE) {
            (
void) (*fp->_close)(fp->_cookie);
            isopen 
= 0;
            f 
= open(file, oflags, DEFFILEMODE);
        }

    }

    sverrno 
= errno;

    
/*
     * Finish closing fp.  Even if the open succeeded above, we cannot
     * keep fp->_base: it may be the wrong size.  This loses the effect
     * of any setbuffer calls, but stdio has always done this before.
     
*/

    
if (isopen && f != wantfd)
        (
void) (*fp->_close)(fp->_cookie);
    
if (fp->_flags & __SMBF)
        free((
char *)fp->_bf._base);
    fp
->_w = 0;
    fp
->_r = 0;
    fp
->_p = NULL;
    fp
->_bf._base = NULL;
    fp
->_bf._size = 0;
    fp
->_lbfsize = 0;
    
if (HASUB(fp))
        FREEUB(fp);
    _UB(fp)._size 
= 0;
    WCIO_FREE(fp);
    
if (HASLB(fp))
        FREELB(fp);
    fp
->_lb._size = 0;

    
if (f < 0{            /* did not get it after all */
        fp
->_flags = 0;        /* set it free */
        FUNLOCKFILE(fp);
        errno 
= sverrno;    /* restore in case _close clobbered */
        
return (NULL);
    }


    
/*
     * If reopening something that was open before on a real file, try
     * to maintain the descriptor.  Various C library routines (perror)
     * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
     
*/

    
if (wantfd >= 0 && f != wantfd) {
        
if (dup2(f, wantfd) >= 0{
            (
void) close(f);
            f 
= wantfd;
        }

    }


    fp
->_flags = flags;
    fp
->_file = f;
    fp
->_cookie = fp;
    fp
->_read = __sread;
    fp
->_write = __swrite;
    fp
->_seek = __sseek;
    fp
->_close = __sclose;

    
/*
     * When opening in append mode, even though we use O_APPEND,
     * we need to seek to the end so that ftell() gets the right
     * answer.  If the user then alters the seek pointer, or
     * the file extends, this will fail, but there is not much
     * we can do about this.  (We could set __SAPP and check in
     * fseek and ftell.)
     
*/

    
if (oflags & O_APPEND)
        (
void) __sseek((void *)fp, (fpos_t)0, SEEK_END);
    FUNLOCKFILE(fp);
    
return (fp);
}


这里以w or a+之类创建文件的时候没办法指定access mode,C lib就没开这种接口,应该就是默认行为,linux上应该就是unmask后的值,猜想这也与各大平台差异太大,没办法在C lib上做wrap吧.

这个时候做作业吧,++困...沉下心来,做完...

5.1 setvbuf 实现 setbuf
Bionic库也是这样做的 setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ)

5.2
fgets, fputs
这两个虽热是和行缓冲相关的函数,但要注意的是fgets读数据读到行末or缓冲区满为止,always会给留一个字符给null; fputs也是将缓冲区内容全部输出,并不care是否有换行符。

5.3 printf返回值是0意味着什么也没输出,输出为空。

5.4 getchar()返回的是int不是char...EOF通常会被定义为 -1 如果char是一个U8,那么就会陷入死循环。

5.5 要在标准IO上使用fsync,先fflush流,把buffer从userspace都写到kernel,然后用fileno拿到fd,fsync(fd)就好了

5.6 这里要说的是,一般情况下(除开输入输出设备)行缓冲,fputs中没有换行符后续不fflush,fgets应该是读不到的。
posted on 2013-05-28 19:24 Torres 阅读(275) 评论(0)  编辑 收藏 引用 所属分类: APUE

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理