這一章會讓你想起一些塵封的記憶
上大學的時候,教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應該是讀不到的。
上大學的時候,教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的實現貼在下面







































































































































這里以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應該是讀不到的。