Linux系統(tǒng)IO中write原型為 ssize_t write(int filedes, const void * buff, size_t nbytes) ;
當(dāng)調(diào)用write寫數(shù)據(jù)的時(shí)候,調(diào)用完成后write直接返回,但是磁盤是個(gè)慢速設(shè)備,操作系統(tǒng)會(huì)將數(shù)據(jù)保存在內(nèi)核中的緩沖區(qū)中,并負(fù)責(zé)異步地將數(shù)據(jù)寫至磁盤。當(dāng)然如果此時(shí)系統(tǒng)宕機(jī)了則會(huì)丟失數(shù)據(jù)。write是系統(tǒng)調(diào)用,每次調(diào)用都會(huì)陷入內(nèi)核,所以選取一個(gè)合適的塊長(zhǎng)度buffsize,并盡量減少它的調(diào)用可以優(yōu)化效率。在ANSI C的標(biāo)準(zhǔn)IO中我們調(diào)用printf/fprintf/fputs等會(huì)以流的方式進(jìn)行處理,我們只需要寫入流中,而不用像write一樣選擇一個(gè)buffsize,因?yàn)闃?biāo)準(zhǔn)IO庫(kù)幫我們處理了很多細(xì)節(jié),例如緩沖區(qū)分配,以優(yōu)化長(zhǎng)度執(zhí)行IO等。這樣的話就會(huì)減少wirte/read系統(tǒng)調(diào)用的數(shù)量,提高效率。但是與此同時(shí)會(huì)引入另外一個(gè)問(wèn)題:數(shù)據(jù)拷貝,例如當(dāng)使用函數(shù)fgets和fputs時(shí),通常需要經(jīng)過(guò)兩次緩沖區(qū):一次是標(biāo)準(zhǔn)IO緩沖區(qū),還有一次是調(diào)用read和write的內(nèi)核緩沖區(qū)。但是總的來(lái)說(shuō)使用標(biāo)準(zhǔn)IO相對(duì)于系統(tǒng)IO來(lái)說(shuō)接口簡(jiǎn)單,且效率相當(dāng)。
標(biāo)準(zhǔn)IO提供了三種類型的緩沖區(qū):全緩存,行緩存和不帶緩存,全緩存只有在緩沖區(qū)滿時(shí)才會(huì)主動(dòng)flush,通常用在對(duì)一個(gè)磁盤文件IO。行緩存在緩沖區(qū)中遇到換行符就會(huì)flush,還有一種情況是需要從標(biāo)準(zhǔn)輸入輸出得到輸入數(shù)據(jù)時(shí)也會(huì)flush緩沖區(qū),行緩存一般用在交互的終端中。不帶緩存則相當(dāng)于直接 write系統(tǒng)調(diào)用輸出,標(biāo)準(zhǔn)出錯(cuò)流stderr通常是不帶緩存的,這就使得出錯(cuò)信息可以盡快顯示出來(lái)。除了默認(rèn)的flush條件外,顯式調(diào)用fflush函數(shù)和程序正常終止時(shí)也會(huì)flush緩沖區(qū)。我們可以使用setbuf/setvbuf來(lái)更改默認(rèn)的緩沖區(qū)長(zhǎng)度,參見(jiàn)APUE 5.4節(jié)。
在使用標(biāo)準(zhǔn)IO的程序中,當(dāng)我們將一個(gè)標(biāo)準(zhǔn)輸出重新定向到一個(gè)文件時(shí),會(huì)將行緩存變?yōu)槿彺?,在某些情況下可能會(huì)導(dǎo)致一些非預(yù)期錯(cuò)誤,比如調(diào)用printf(“*****\n”)時(shí),當(dāng)以交互方式運(yùn)行該程序時(shí),會(huì)正常輸出。但是當(dāng)將標(biāo)準(zhǔn)輸出重新定向到一個(gè)文件時(shí),緩沖區(qū)區(qū)變?yōu)槿彺妫琾rintf就不會(huì)正常輸出,該行數(shù)據(jù)仍在緩沖區(qū)中。如果此時(shí)再fork一個(gè)子進(jìn)程,數(shù)據(jù)空間被復(fù)制到子進(jìn)程中時(shí),該緩沖區(qū)數(shù)據(jù)也被復(fù)制到子進(jìn)程中。接著在子進(jìn)程中如果輸出則會(huì)刷新之前在緩沖區(qū)的內(nèi)容,產(chǎn)生一些非預(yù)期的輸出。
在網(wǎng)絡(luò)編程中,應(yīng)該直接使用系統(tǒng)IO,標(biāo)準(zhǔn)IO為提升性能而引入緩沖機(jī)制增加了網(wǎng)絡(luò)應(yīng)用程序的復(fù)雜性。并且,某種意義上說(shuō)標(biāo)準(zhǔn)IO流是全雙工的,能同時(shí)執(zhí)行輸入和輸出,然而對(duì)流的限制和對(duì)套接字的限制,有時(shí)候會(huì)互相沖突。(參見(jiàn)CSAPP P611)