C語言 流緩衝 Stream Buffering


From : https://www.gnu.org/software/libc/manual/html_node/Stream-Buffering.html
譯者:李秋豪
html

12.20 流緩衝

一般狀況下,寫入流的字符會在寫入前進行累積而後以塊的形式異步轉送而非由應用程序立刻輸出。類似的,流一般從主機環境以塊的形式而非字節-字節的形式讀入數據。這稱爲緩衝。node

若是你正在寫一個用流來交互的程序,當你設計交互接口時你須要理解緩衝是如何工做的。不然,你可能會發現輸出(例如進程提示信息)不輸出理想值,或者出現奇怪的行爲。數組

這一節講解的是在流/文件/設備之間傳輸設備,並不會涉及echoing, flow control, 特殊設備。若是想了解關於終端設備的通用控制操做符的信息,參考Low-Level Terminal Interface異步

你能夠經過使用底層I/O函數與文件描述符來來避免使用流緩衝。參考 Low-Level I/Oide

12.20.1 概念與術語

一共有三種緩衝策略:(譯者注:緩衝策略是寫入流/文件的充分條件,不是必要的。緩衝區存在的意義就是在使用「Stream-level I/O」時從緩衝區進行異步塊寫入/讀出,這樣能夠在設備堵塞的時候或者有大量的寫操做時加快效率。若是一次只寫入少許數據,內核一看沒有堵塞,「乾脆」就把緩衝區的內容寫入了,反正放着也是放着)函數

  • 無緩衝 unbuffered :從一個無緩衝的流中讀寫會立刻產生效果
  • 行緩衝 line buffered:當遇到一個換行符的時候字符會以塊的形式讀寫。
  • 滿緩衝 fully buffered:字符會以任意大小的塊寫入讀出。(真的是直譯。。感受和網上一些說滿的時候纔讀寫的說法不同,說明多是不堵塞的時候就讀寫緩衝區,最多等到緩衝區滿

新開的流通常是滿緩衝的,只有一個例外:當流是一個可交互設備(例如終端)的時候,流將變爲行緩衝。若是想了解關於如何選擇緩衝策略,參考 Controlling Buffering 。一般狀況下,默認會選擇出最方便的緩衝策略。ui

在行緩衝下,以換行符結束的信息會立刻輸出到交互設備裏——這一般是你想要的。不以換行符結尾的信息可能不會立刻顯示到交互設備,因此若是你想要當即顯示,你須要在寫入後使用fflush, 參考 Flushing Buffers.(譯者注:一般使用fprintf+stderr,由於stderr默認是無緩衝的)this

12.20.2 清除緩衝區

清除緩衝區意味着當即以塊的形式寫入緩衝區內收集的內容。有不少狀況下緩衝區會自動清除:操作系統

  • 當輸出緩衝區滿後嘗試輸出。
  • 當流關閉的時候。參考 Closing Streams
  • 當程序經過調用exit結束的時候。參考 Normal Termination
  • 當向行緩衝緩衝區寫入換行符時。
  • 當從本文件的任意流讀入時。

If you want to flush the buffered output at another time, call fflush, which is declared in the header file stdio.h.若是你想要在別的時候清除緩衝區,可使用stdio.h中聲明的fflush翻譯

  • Function: int fflush (FILE *stream)

    Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.這個函數會致使與stream關聯的緩衝區被寫入到文件中,若是stream是一個空指針,那麼fflush會致使目前打開的全部流的緩衝區被清除。這個函數將返回EOF若是發生一個寫入錯誤,不然返回0。

  • Function: int fflush_unlocked (FILE *stream)

    Preliminary: | MT-Safe race:stream | AS-Unsafe corrupt | AC-Unsafe corrupt | See POSIX Safety Concepts. fflush_unlocked函數和fflush相同,除了它不會隱式的阻塞(block)這個stream流。

此處省略一些...

  • Function: void **_flushlbf** (void)

    Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.該函數會清除全部的行緩衝流的緩衝區,聲明在stdio_ext.h頭文件中。

兼容性: 有一些腦子壞掉的操做系統老是對那些以換行符爲導向的輸入「念念不忘」——清除一個行緩衝會致使一個換行符被寫入。幸運的是,這個特性愈來愈少見,而且對於GNU C Library 你不用擔憂。

有一些狀況下不去手動清除緩衝區而是忘記這件事多是一個更好的選擇,由於讀寫可能不是必要的並且是相對花費大的。

  • Function: void **__fpurge** (FILE *stream)

    Preliminary: | MT-Safe race:stream | AS-Unsafe corrupt | AC-Unsafe corrupt | See POSIX Safety Concepts.__fpurge 函數會把stream流的緩衝區清空,可是不會產生讀寫!聲明在stdio_ext.h。

12.20.3 控制緩衝策略

在打開一個流以後,你經過使用setvbuf選擇該流使用何種緩衝策略。

如下列出的函數和宏在頭文件stdio.h中聲明。

  • Function: int setvbuf (FILE *stream, char buf, int mode, size_t size)*

    Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.這個函數是用來定義stream流該採用何種緩衝策略——能夠是 _IOFBF (滿緩衝), _IOLBF (行緩衝), or _IONBF (無緩衝)。若是你輸入的一個空指針做爲buf參數,那麼setvbuf會自動使用malloc申請一塊內存,當你關閉流的時候,緩衝區會被清除釋放掉。不然buf對應的內存塊至少應該是size大小。你不該該釋放掉buf對應的空間只要流尚未關閉。你應該確保buf對應的內存是靜態存儲的(例如使用malloc)。使用一個自動存儲期限的buf塊不是一個好的選擇——除非在退出當前塊以前關掉了流。當buf對應的數組塊是緩衝區的時候,stream流i/o函數會使用這個內存塊做爲一些內部用途——因此你不該該試着去直接訪問這個數組的值當它被使用的時候。 setvbuf 成功時返回0,不然返回非零數當mode是不可取的或者要求不能被知足。

  • Macro: int **_IOFBF**

    這個宏的值是一個整數常量表達式,能夠被setvbuf函數用來是緩衝區是滿緩衝的。

  • Macro: int **_IOLBF**

    這個宏的值是一個整數常量表達式,能夠被setvbuf函數用來是緩衝區是行緩衝的。

  • Macro: int **_IONBF**

    這個宏的值是一個整數常量表達式,能夠被setvbuf函數用來是緩衝區是無緩衝的。

  • Macro: int BUFSIZ

    這個宏的值是一個整數常量表達式,能夠被setvbuf函數用來表達size,這個值被保證最小是256。 BUFSIZ 是由操做系統選擇的,以此來提升i/o的效率。因此使用 BUFSIZ 做爲setvbuf的大小值是一個很好的選擇。事實上,你能夠用過fstat 系統調用得到一個更好的值(在文件屬性的 st_blksize 區域),參考 Attribute Meanings.有時候人們使用 BUFSIZ做爲申請內存空間的大小值(或者做爲i/o操做的內存,例如fgets)——這沒什麼特別的理由,除了能提升一些i/o效率。

  • Function: void setbuf (FILE *stream, char buf)*

    Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.If buf is a null pointer, the effect of this function is equivalent to calling setvbuf with a mode argument of_IONBF. Otherwise, it is equivalent to calling setvbuf with buf, and a mode of _IOFBF and a size argument of BUFSIZ.The setbuf function is provided for compatibility with old code; use setvbuf in all new programs.若是buf是一個空指針,這個函數的效果等於setvbuf使用_IONBF.不然,等效於使用 setvbuf_IOFBF BUFSIZ這兩個參數。該函數是爲了兼容一些老的代碼,在新的程序中請使用setvbuf.

  • Function: void setbuffer (FILE *stream, char buf, size_t size)*

    Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.

    省略...這個函數是爲了兼容一些BSD的老舊代碼。請使用setvbuf.

  • Function: void setlinebuf (FILE *stream)

    Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.

    省略...這個函數是爲了兼容一些BSD的老舊代碼。請使用setvbuf.

    剩下一些不經常使用的函數就不翻譯了。

相關文章
相關標籤/搜索