IO_緩衝和非緩衝

這兩天在項目原有版本的基礎上增長了一段新的協議實現代碼,所以須要和平臺進行聯調。考慮到更好地進行調試,我在代碼中添加了一段相似日誌記錄的代碼,已獲取通信的報文內容和當時的環境參數內容,就是建立一個文件,使用標準IO的fopen、fprintf進行輸出記錄。可是在調試中,剛開始我就傻眼了,文件建立成功了,可是實時查看居然沒有任何數據記錄。通過半天的擔驚受怕和反覆排查,發現是被標準IO的緩衝機制擺了一道,慚愧呀。。。函數

 

下面給出一個示例程序,模擬個人項目程序:調試

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
int main() 
{
    FILE* fp=NULL;
    const char *filename_1="test_fprintf.log";
    const char *filename_2="test_write.log";
    int fd;
    fp = fopen(filename_1, "wb");
    if(fp == NULL) 
    {
        printf("open %s failed, %s\n", filename_1, strerror(errno));
        return -1;
    }
    //setbuf(fp, NULL);
    //setvbuf(fp, NULL, _IONBF, 0);
    fd = open(filename_2, O_WRONLY|O_CREAT|O_EXCL, 0666);
    if(fd < 0) 
    {
        printf("open %s failed, %s\n", filename_2, strerror(errno));
        return -1;
    }
    while(1) 
    {
        fprintf(fp, "test fprintf.\n");
        fprintf(fp, "-------test fprintf.\n");
        fprintf(fp, "=======test fprintf.\n");
        //fflush(fp);
        write(fd, "test open.\n", sizeof("test open.\n"));
        write(fd, "--------test open.\n", sizeof("--------test open.\n"));
        write(fd, "--------test open.\n", sizeof("--------test open.\n"));
        sleep(1);
    }
    return 0;
}
後臺運行上面的示例程序,而後實時查看兩個日誌文件,會發現testfrpintf.log文件一開始一直都是空的,而testwrite.log則是不斷有數據寫入,以下狀態: 日誌

我當時就是奇怪爲何文件會是空的。能夠看出標準IO會緩衝4096Bytes的數據,當達到這麼多數據時纔會進行實際的磁盤寫入,而系統調用write則是直接寫入,不進行緩衝。code

標準IO庫提供緩衝的目的是儘量減小使用read和write調用的次數,下降執行IO的時間,它提供三種類型的緩衝:string

  1. 全緩衝。在填滿標準IO緩衝區後才進行實際IO操做,對於磁盤文件一般就是全緩衝,上面的示例就是採用緩衝。
  2. 行緩衝。在輸入和輸出中遇到換行符時進行實際的IO操做,當涉及到一個終端時,一般使用行緩衝。使用最頻繁的printf函數就是採用行緩衝,因此感受不出緩衝的存在。
  3. 不帶緩衝。標準IO庫不對字符進行緩衝存儲。標準出錯流stderr一般是不帶緩衝的。

ISO C要求下列緩衝特徵:it

  • 當且僅當標準輸入和標準輸出並不涉及交互式設備時,它們纔是全緩衝的。
  • 標準出錯決不會是全緩衝。

不少系統默認使用下列類型的緩衝:io

  • 標準出錯是不帶緩衝的。
  • 如如果涉及終端設備的其它流,則他們是行緩衝的;不然是全緩衝的。

固然,對於標準IO流,咱們也能夠更改緩衝類型,或者是直接刷新。ISO C中提供下面兩個函數以更改緩衝類型:table

1 void setbuf(FILE *fp, char *buf); //buf爲NULL,表示關閉緩衝
2 int setvbuf(FILE *fp, char *buf, int mode, size_t size); //成功返回0,出錯返回非0值

setvbuf函數中的mode參數能夠爲:_IOBUF 全緩衝, _IOLBF 行緩衝, _IONBF 不帶緩衝,若是buf爲NULL, 則標準IO庫將自動地爲該流分配適當長度(常量BUFSIZ)的緩衝區。通常而言,應由系統選擇緩衝區的長度,並自動分配緩衝區,這樣關閉流時,標準IO庫將自動釋放緩衝區。test

強制沖洗一個流,使用函數:後臺

1 int fflush(FILE *fp); //成功返回0, 出錯返回EOF

項目中我是使用這個函數解決鬱悶的。

1 fflush(NULL); //沖洗全部輸出流
相關文章
相關標籤/搜索