緩沖區(qū)的認(rèn)識(shí)
緩沖區(qū)(buffer)是存儲(chǔ)數(shù)據(jù)的臨時(shí)存儲(chǔ)區(qū)域。當(dāng)我們用C語(yǔ)言向文件中寫入數(shù)據(jù)時(shí),數(shù)據(jù)并不會(huì)直接的寫到文件中,中途還經(jīng)過(guò)了緩沖區(qū),而我們需要對(duì)緩沖區(qū)的數(shù)據(jù)進(jìn)行刷新,那么數(shù)據(jù)才算寫到文件當(dāng)中。而緩沖區(qū)通常是一塊內(nèi)存區(qū)域,可以是數(shù)組、隊(duì)列、鏈表等數(shù)據(jù)結(jié)構(gòu)。
代碼舉例
int main()
{
//C接口
FILE* fp=fopen("log.txt","w");//創(chuàng)建文件
const char* buffer = "hello buffer\n";
fwrite(buffer,strlen(buffer),1,fp);//文件寫入
//系統(tǒng)接口
close(fp->_fileno);
return 0;
}
此時(shí)的數(shù)據(jù)其實(shí)就是寫進(jìn)了緩沖區(qū)中,但是我們此時(shí)的調(diào)用接口是不一樣的,關(guān)閉文件調(diào)用的是系統(tǒng)調(diào)用接口,而且FILE結(jié)構(gòu)體中是封裝了文件描述符的。先認(rèn)識(shí)后續(xù)會(huì)講述原因。
其實(shí)我們是可以將我們緩沖區(qū)中的數(shù)據(jù)給刷新出來(lái):
int main()
{
FILE* fp=fopen("log.txt","w");
const char* buffer = "hello buffer\n";
fwrite(buffer,strlen(buffer),1,fp);
fflush(fp);//刷新緩沖區(qū)
close(fp->_fileno);
return 0;
}
?為什么要有緩沖區(qū)的存在
其實(shí)緩沖區(qū)的存在就是為了減少對(duì)數(shù)據(jù)的訪問(wèn)次數(shù),當(dāng)我們輸入輸出數(shù)據(jù)的時(shí)候,其實(shí)就是對(duì)文件信息進(jìn)行交互的(一切皆文件)。我們?yōu)榱吮苊饷恳淮蔚奈募L問(wèn)IO操作,從而會(huì)降低效率,所以說(shuō)可以建立一個(gè)像緩沖區(qū)這樣的中轉(zhuǎn)站,將數(shù)據(jù)與緩沖區(qū)交互,然后將所有的數(shù)據(jù)都接收處理好了以后再交給文件。
緩沖區(qū)的刷新方式
- 立即刷新(無(wú)緩沖)
- 行刷新(行緩沖)
- 緩沖區(qū)滿了刷新(全緩沖)
- 強(qiáng)制刷新
一般對(duì)于顯示器文件的刷新方式是行刷新(\n也是進(jìn)行行刷新),而一般磁盤上的文件的刷新方式就是緩沖區(qū)滿了再刷新。?我們也可以通過(guò)fflush函數(shù)強(qiáng)制的進(jìn)行刷新緩沖區(qū)。而且進(jìn)程退出后都會(huì)采取強(qiáng)制刷新,但是此時(shí)如果文件已經(jīng)close的話(底層fd沒(méi)了),數(shù)據(jù)依舊刷不進(jìn)去的。
此時(shí)就可以淺淺的解釋我們開(kāi)始寫的代碼的,因?yàn)槲覀兊囊话阄募乃⑿虏呗允蔷彌_區(qū)滿了才刷新的,這正是因?yàn)槲覀兿騦og.txt這個(gè)文件里寫的數(shù)據(jù)沒(méi)有寫滿緩沖區(qū),所以導(dǎo)致緩沖區(qū)沒(méi)有刷新,從而該文件中并沒(méi)有數(shù)據(jù)。其實(shí)如果你多寫一些數(shù)據(jù)進(jìn)去的話其實(shí)是可以寫滿的。
緩沖區(qū)與操作系統(tǒng)無(wú)關(guān)
?結(jié)論:我們寫代碼時(shí)的緩沖區(qū)其實(shí)是屬于C語(yǔ)言的,與操作系統(tǒng)并無(wú)關(guān)系。
int main() { FILE* fp=fopen("log.txt","w"); const char* buffer = "helllo buffer\n"; fwrite(buffer,strlen(buffer),1,fp); fclose(fp);//C語(yǔ)言接口 return 0; }
?該段代碼的區(qū)別就是用了C語(yǔ)言接口關(guān)閉文件。而我們開(kāi)頭的那段代碼是系統(tǒng)調(diào)用關(guān)閉文件。僅僅換了一種關(guān)閉方式就導(dǎo)致了文件中一個(gè)有數(shù)據(jù)一個(gè)沒(méi)數(shù)據(jù)。所以說(shuō)可以知道,C語(yǔ)言中的fclose其實(shí)是封裝了系統(tǒng)調(diào)用的close,但是還多了一個(gè)步驟:刷新緩沖區(qū)。
也可以說(shuō)明系統(tǒng)調(diào)用接口其實(shí)是沒(méi)有緩沖區(qū)這個(gè)概念的,緩沖區(qū)其實(shí)是我們C語(yǔ)言庫(kù)中后期封裝好的。
?經(jīng)典樣例
代碼一:
int main() { printf("C:printf\n"); fprintf(stdout,"C:fprintf\n"); fputs("C:fputs\n",stdout); const char* arr = "system:write\n"; write(1,arr,strlen(arr)); return 0; }
代碼二:
int main() { printf("C:printf\n"); fprintf(stdout,"C:fprintf\n"); fputs("C:fputs\n",stdout); const char* arr = "system:write\n"; write(1,arr,strlen(arr)); fork();//創(chuàng)建子進(jìn)程 return 0; }
就上面的兩段代碼唯一的區(qū)別就是在程序結(jié)束之前是否創(chuàng)建了子進(jìn)程。
現(xiàn)象就是:代碼一沒(méi)有創(chuàng)建子進(jìn)程,而且就如我們意想的結(jié)果一樣正常打印數(shù)據(jù)到log.txt文件當(dāng)中,而代碼二在打印結(jié)束的時(shí)候創(chuàng)建了子進(jìn)程,最終log.txt文件中的數(shù)據(jù)打印了兩份,除了系統(tǒng)調(diào)用write函數(shù)之外。
其實(shí)在我們./test.exe > log.txt 將本應(yīng)該打印到顯示器文件的數(shù)據(jù)重定向到log.txt文件當(dāng)中時(shí),就改變了緩沖區(qū)的刷新策略,從原先的行數(shù)新變成了緩沖區(qū)滿了再刷新。所以在執(zhí)行fork函數(shù)創(chuàng)建子進(jìn)程之前的所有數(shù)據(jù)依舊還是存在緩沖區(qū)當(dāng)中,而創(chuàng)建子進(jìn)程后,父子進(jìn)程代碼共享,數(shù)據(jù)采用寫時(shí)拷貝的方式存在著。當(dāng)假設(shè)父進(jìn)程先結(jié)束退出以后,此時(shí)父進(jìn)程的緩沖區(qū)就會(huì)被強(qiáng)制刷新(也就是相當(dāng)于清空緩沖區(qū)數(shù)據(jù)),而此時(shí)的子進(jìn)程必然是會(huì)發(fā)生寫時(shí)拷貝,數(shù)據(jù)獨(dú)有一份,所以最終子進(jìn)程退出時(shí)緩沖區(qū)的數(shù)據(jù)也會(huì)被強(qiáng)制刷新,所以最終數(shù)據(jù)就有兩份了。
而針對(duì)于系統(tǒng)調(diào)用write函數(shù)并不是將數(shù)據(jù)寫進(jìn)緩沖區(qū)當(dāng)中,而是直接寫到操作系統(tǒng)中,因此以上操作就與該函數(shù)無(wú)關(guān)。
緩沖區(qū)在哪里??
我們知道緩沖區(qū)與操作系統(tǒng)無(wú)關(guān),所以緩沖區(qū)在哪里呢,其實(shí)就在FILE的結(jié)構(gòu)體中。
就那我們比較熟悉的函數(shù)fflush,該函數(shù)的作用是刷新緩沖區(qū),而參數(shù)就是FILE*的文件指針,所以此時(shí)其實(shí)就可以看出端倪了。
FILE其實(shí)是一個(gè)結(jié)構(gòu)體,我們前面知道FILE結(jié)構(gòu)體當(dāng)中封裝了文件描述符,其實(shí)也有緩沖區(qū),其實(shí)就是一些指針。
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-809141.html
?????????文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-809141.html
到了這里,關(guān)于用Linux的視角來(lái)理解緩沖區(qū)概念的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!