天天看點

檔案IO和标準I/O(緩沖IO)概念講解、以及相關函數使用對比分析

檔案IO和标準I/O(緩沖IO)對比分析

1 檔案I/O

  • 檔案I/O:檔案I/O稱之為不帶緩存的IO(unbuffered I/O)。不帶緩存指的是每個read,write都調用核心中的一個系統調用,資料直接在使用者空間緩沖區和核心高速緩沖區之間複制
  • read()和write()系統調用在操作磁盤檔案的時候不會直接發起磁盤通路,而是僅僅在使用者空間緩沖區和核心緩沖區高速緩存之間複制資料,複制完畢,系統調用就會結束,然後就是核心自己解決資料在核心緩沖區到磁盤傳遞的問題
    1. 目的:使得I/O調用更加快速
    2. 與檔案發生大量的資料傳輸的時候,盡量采用大的緩沖區資料據,以及執行更少的系統調用,可以大大提升I/O性能
    3. write調用把使用者空間緩沖區的資料複制到核心緩沖區之後,由核心在把資料寫入到磁盤,如果此時其它程序通路該檔案,那麼核心會把核心緩沖區的資料傳遞給該程序
    4. read系統調用從核心緩沖區讀取資料的時候,會把緩沖區的資料讀取大最大,讀完之後,系統會把下一段的資料從磁盤都入到核心高速緩沖區
  • 檔案空洞:程式的偏移量跨越了檔案結尾,read調用會傳回0,write确可以在檔案結尾後面的任意位置寫入資料,在檔案結尾這後面的一部分資料空間就叫做檔案空洞,然而檔案空洞不會占用磁盤空間,隻有在檔案空洞中寫入了資料之後,系統才會為之配置設定空間
  • open調用中,參數O_CREAT和O_EXCL一般放在一起用,O_EXCL用來判斷檔案是否存在,在建立檔案的時候,如果檔案已經存在,那麼open就會報錯,如果不使用O_EXCL标記,就算檔案存在,open調用建立檔案的時候,open調用也會成功,這就導緻,一個檔案從屬兩個程序,這樣是不對的,兩個檔案可以以一個寫,另外一個讀的方式打開同一個檔案,但是不能同時建立檔案,是以這也是參數O_CREAT和O_EXCL放在一起使用的原因,讓一個檔案以獨占的方式被建立,兩個标志在一起屬于一個原子操作,是不能被打斷的
  • fcntl函數,判斷檔案的通路模式的時候,隻讀、隻寫、可讀可寫,三個常量不與檔案标志位的單個bit位對應,要判斷其通路模式,需要把擷取的flag和O_ACCMODE相與的結果在和O_RDWR這類的标記比較
    檔案IO和标準I/O(緩沖IO)概念講解、以及相關函數使用對比分析
  • 可以使用fcntl修改的某些檔案的标志位隻有,O_APPEND、O_NONBLOCK、O_NOATIME、O_ASYNV、O_DIRECT,系統忽略其它标記的修改操作
  • fcntl尤其适用的場景:
    1. 檔案不是由調用程序打開,比如标準輸入、輸出等
    2. 檔案描述符通過open以外的系統調用打開,比如socket()、pipe()
    3. fcntl使用舉例:
      檔案IO和标準I/O(緩沖IO)概念講解、以及相關函數使用對比分析

2 檔案I/O緩沖(标準I/O)

  • 标準I/O是ANSI C建立的一個标準I/O模型,是一個标準函數包和stdio.h頭檔案中的定義,具有一定的可移植性。标準I/O庫處理很多細節。例如緩存配置設定,以優化長度執行I/O等。标準的I/O提供了三種類型的緩存,相當于在檔案I/O上又進行了一些封裝
    1. 全緩存:當填滿标準I/O緩存後才進行實際的I/O操作,例如磁盤塊讀寫
    2. 行緩存:當輸入或輸出中遇到新的換行符時,标準I/O庫執行I/O操作。
    3. 不帶緩存:stderr就是了
  • 标準I/O帶緩沖的原因:使用标準I/O,比如fopen,會在調用的時候建立一個标準I/O緩沖區,當達到标準I/O的準則的時候,在把标準I/O緩沖區的資料寫入到核心緩沖區中,是以在使用标準I/O的時候,有使用者空間緩沖區,标準I/O緩沖區,核心資料高速緩沖區這幾個個緩沖區
    /**************************
    函數功能:設定标準I/O的緩沖工作模式
    傳回值:The  function  setvbuf()  returns  0 on success.  It returns nonzero on
           failure (mode is invalid or the request cannot be honored).  It may set
           errno on failure.
    **************************/
    #inclde <stdio.h>
        
    int setvbuf(FILE *stream, char *buf, int mode, size_t size);
    /*參數
    stream:指代标準流,stdin、stdout、stderr
    buf:儲存了開辟的标準I/O緩沖區,設定為NULL的話,系統自動在記憶體中開辟一個标準I/O緩沖區
    mode:标準I/O的工作模式
    	1.标準I/O不緩沖
    	2.采用行緩沖
    	3.采用全緩沖	
    size:标準I/O緩沖區大小,如果buf為NULL,size會被忽略
    */
    
    /**************************
    函數功能:強制把标準I/O緩沖區中的内容,重新整理到核心緩沖區中
    傳回值:Upon successful completion 0 is returned.  Otherwise, EOF  is  returned
           and errno is set to indicate the error.
    **************************/
    #include <stdio.h>
    
    int fflush(FILE *stream);
    /*參數:
    stream指代标準流指針
    */
               

3 核心高速緩沖區的控制

  • 同步I/O資料完整性:
    1. 對讀操作來說:意味着被請求的檔案資料已經從磁盤傳遞到程序
    2. 對寫操作而言:檔案資料已經傳遞到磁盤,但是某些檔案中繼資料就算被修改了,比如檔案的時間戳,如果沒有寫入磁盤,也滿足資料完整性
  • 同步I/O檔案完整性:是同步I/O資料完整性的超集,此時中繼資料也是考慮的因素之一,才能保證同步I/O檔案完整性
  • 如果open調用指定了O_SYNC标志,那麼write調用會直接把使用者空間的資料直接重新整理到磁盤中,而不會複制到核心緩沖區,但是盡量不使用這個标志,原因如下圖:
  • 檔案IO和标準I/O(緩沖IO)概念講解、以及相關函數使用對比分析
  • 緩沖示意圖:
    檔案IO和标準I/O(緩沖IO)概念講解、以及相關函數使用對比分析