一、什麼是緩存I/O(Buffered I/O)
緩存I/O又被稱作標準I/O,大多數文件系統默認I/O操作都是緩存I/O。在Linux的緩存I/O機制中,操作系統會將I/O的數據緩存在文件系統的頁緩存(page cache)中,也就是說,數據會先被拷貝到操作系統內核的緩衝區中,然後纔會從操作系統內核的緩衝區拷貝到應用程序的地址空間。
1.緩存I/O有以下優點:
A.緩存I/O使用了操作系統內核緩衝區,在一定程度上分離了應用程序空間和實際的物理設備。
B.緩存I/O可以減少讀盤的次數,從而提高性能
當應用程序嘗試讀取某塊數據的時候,如果這塊數據已經存放在頁緩存中,那麼這塊數據就可以立即返回給應用程序,而不需要經過實際的物理讀盤操作。當然,如果數據在應用程序讀取之前並未被存放在頁緩存中,那麼就需要先將數據從磁盤讀到頁緩存中去。對於寫操作來說,應用程序也會將數據先寫到頁緩存中去,數據是否被立即寫到磁盤上去取決於應用程序所採用的寫操作機制:如果用戶採用的是同步寫機制,那麼數據會立即被寫回到磁盤上,應用程序會一直等到數據被寫完爲止;如果用戶採用的是延遲寫機制,那麼應用程序就完全不需要等到數據全部被 寫回到磁盤,數據只要被寫到頁緩存中去就可以了。在延遲寫機制的情況下,操作系統會定期地將放在頁緩存中的數據刷到磁盤上。與異步寫機制不同的是,延遲寫機制在數據完全寫到磁盤上得時候不會通知應用程序,而異步寫機制在數據完全寫到磁盤上得時候是會返回給應用程序的。所以延遲寫機制本省是存在數據丟失的風險的,而異步寫機制則不會有這方面的擔心。
2.緩存I/O的缺點
在緩存I/O機制中,DMA方式可以將數據直接從磁盤讀到頁緩存中,或者將數據從頁緩存直接寫回到磁盤上,而不能直接在應用程序地址空間和磁盤之間進行數據傳輸,這樣的話,數據在傳輸過程中需要在應用程序地址空間和頁緩存之間進行多次數據拷貝操作,這些數據拷貝操作說帶來的cpu以及內存開銷是非常大的。
二、文件指針
FILE指針:每個被使用的文件都在內存中開闢一個區域,用來存放文件的有關信息,這些信息是保存在一個結構體類型的變量中,該結構體類型是由系統定義的,取名爲FILE。
標準I/O庫的所有操作都是圍繞流(stream)來進行的,在標準I/O中,流用FILE *來描敘的。
其在Linux操作系統中的定義:
三、行緩衝、全緩衝、不緩衝的定義
1.Fully buffered means that I/O takes place only when the buffer is fully, the process explicitly calls fflush, or the process terminates by calling exit. A common size for the standard I/O buffer is 4096 bytes;
2. Line buffered means that I/O takes place when a newline is encountered, when the process calls fflush, or when the process terminates by calling exit.
3. Unbuffered means that I/O take place each time a standard I/O output function is called.
Most unix implementations of the standard I/O libarary use the following rules.
1. Standard error is always unbuffered.
2. Standard input and standard output are fully buffered, unless they refer to a terminal device, in which case, they are line buffered.
3. All other streams are fully buffered unless they refer to a terminal device,
in which case, they are line buffered.
四、一步步探究
- #include <stdio.h>
- int stream_attribute(FILE *fp)
- {
- if(fp->_flags & _IO_UNBUFFERED)
- {
- printf("The IO type is unbuffered\n");
- }else if(fp->_flags & _IO_LINE_BUF){
- printf("The IO type is line buf\n");
- }else{
- printf("The IO type is full buf\n");
- }
- printf("The IO size : %d\n",fp->_IO_buf_end - fp->_IO_buf_base);
- return 0;
- }
- int main()
- {
- FILE *fp;
- stream_attribute(stdin);
- printf("___________________________________\n\n");
- stream_attribute(stdout);
- printf("___________________________________\n\n");
- stream_attribute(stderr);
- printf("___________________________________\n\n");
- if((fp = fopen("test.txt","w+")) == NULL)
- {
- perror("fail to fopen");
- }
- stream_attribute(fp);
- return 0;
- }
運行結果:
我們修改一下代碼再看
- #include <stdio.h>
- int stream_attribute(FILE *fp)
- {
- if(fp->_flags & _IO_UNBUFFERED)
- {
- printf("The IO type is unbuffered\n");
- }else if(fp->_flags & _IO_LINE_BUF){
- printf("The IO type is line buf\n");
- }else{
- printf("The IO type is full buf\n");
- }
- printf("The IO size : %d\n",fp->_IO_buf_end - fp->_IO_buf_base);
- return 0;
- }
- int main()
- {
- FILE *fp;
- getchar();
- stream_attribute(stdin);
- printf("___________________________________\n\n");
- stream_attribute(stdout);
- printf("___________________________________\n\n");
- stream_attribute(stderr);
- printf("___________________________________\n\n");
- if((fp = fopen("test.txt","w+")) == NULL)
- {
- perror("fail to fopen");
- }
- printf("before write:\n");
- stream_attribute(fp);
- fputc('a',fp);
- printf("after write:\n");
- stream_attribute(fp);
- return 0;
- }
運行結果:
從以上我們可以看出,標準I/O並不是一開始就分配的,只有進行了輸入或者輸出的操作才進行分配的,標準輸入和標準輸出默認是全緩衝,但是如果和終端關了就是行緩衝。可以看到在linux操作系統中行緩衝的大小是1k,全緩衝的大小是4k。
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
閱讀(31) | 評論(0) | 轉發(0) |