標準I/O

  對於標準I/O都是圍繞流進行操做,當用標準I/O庫打開一個文件時,使一個流與一個文件相關聯。網絡

  流的定向決定了所讀寫的字符是單個字節仍是多字節。當流建立時並無定向,若在未定向的流上使用一個多字節I/O函數,則流設置爲寬定向,若使用單字節函數,流定向爲字節定向。分佈式

  FILE一般是一個結構,它包含了標準I/O庫管理流所需的信息:用於實際I/O文件的描述符,指向流緩衝區的指針,緩衝區長度,當前緩衝區的字符數以及出錯標誌。函數

  標準IO流操做讀寫普通文件是使用全緩衝的,默認緩衝區長度是該文件系統優先選用的IO長度(從stat結構獲得的st_blksize值)性能

緩衝

  1. 全緩衝(默認4096字節) :全緩衝指的是系統在填滿標準IO緩衝區以後才進行實際的IO操做;注意,對於駐留在磁盤上的文件來講一般是由標準IO庫實施全緩衝。
  2. 行緩衝 (默認1024字節):在這種狀況下,標準IO在輸入和輸出中遇到換行符時執行IO操做,這容許咱們一次輸出一個字符,可是隻有寫了實際一行後才進行I/O操做;注意,當流涉及終端的時候,一般使用的是行緩衝。對於行緩衝有兩個限制:一,由於標準I/O收集每一行緩衝區的長度是固定的,因此只要填滿了緩衝區,那麼即便尚未寫入一個換行符,也進行I/O操做。二,任什麼時候候只要經過標準I/O庫從<a>一個不帶緩衝的流(須要從內核讀取數據),<b>一個行緩衝的流(它從內核請求須要的數據——數據可能在緩衝區中,不須要從內核讀取)獲得輸入數據,那麼就會沖洗全部行緩衝輸出的流
  3. 無緩衝 :無緩衝指的是標準IO庫不對字符進行緩衝存儲;注意,標準出錯流stderr一般是無緩衝的。

  沖洗:說明標準I/O緩衝區的寫操做,緩衝區可能由標準I/O例程自動沖洗(當一個緩衝區滿時)或者調用fflush沖洗一個流。在標準I/O方面,沖洗兩層含義:1.將緩衝區中的內容寫到磁盤上(緩衝區可能只是部分填滿)2.驅動程序方面(tcflush)表示丟棄已存儲在緩衝區中的內容。spa

  緩衝特徵:指針

  • 標準輸入和標準輸出不指向交互式設備才指向全緩衝,指向交互設備是行緩衝
  • 標準錯誤毫不是全緩衝

  打開或關閉緩衝機制——這些函數必定要在流被打開後調用rest

#include <stdio.h>
void setbuf(FILE *restrict fp, char *restrict buf);
int setvbuf(FILE *restrict, char *restrict buf, int mode, size_t size);
//成功返回0,出錯返回非0

  buff指向一個長度爲BUFSIZ的緩衝區(定義在該頭文件中),一般在此以後是全緩衝的,可是一個流若是與終端設備相關,某些設備也將其設置爲行緩衝的,buf爲NULL時關閉緩衝。code

  若是buff爲NULL,標準I/O庫自動爲其分配適當的緩衝區長度,改長度由BUFSIZ指定。從函數返回以前關閉該流,緩衝區的一部分用於存放他本身的管理操做信息,因此緩衝區存放的字節數實際少於size。通常狀況下,系統選擇分配緩衝區的長度,並自動分配緩衝區,在這種狀況下,關閉此流時,標準I/O庫自動釋放緩衝區。對象

  setvbuf中的modeblog

  1. _IOFBF(滿緩衝):當緩衝區爲空時,從流讀入數據。或者當緩衝區滿時,向流寫入數 據。
  2. _IOLBF(行緩衝):每次從流中讀入一行數據或向流中寫入一行數據。
  3. _IONBF(無緩衝):直接從流中讀入數據或直接向流中寫入數據,而沒有緩衝區。

  強制沖洗緩衝

#include <stdio.h>
int fflush(FILE *fp);
//成功返回0出錯返回非0

打開流

  除非流引用終端設備,不然按系統默認,流被打開是全緩衝的,若引用終端設備則是行緩衝。

#include <stdio.h>  
FILE* fopen(const char* restrict pathname, const char* restrict type);  
FILE* freopen(const char* restrict pathname, const char* restrict type, FILE* restrict fp);  
FILE* fdopen(int filedes, char* type); 

  fopen打開一個指定的文件。

  freopen在一直指定的流上打開一個指定的文件,如若該流已經打開,則先關閉該流。若是該流已經定向,則freopen清除該定向。此函數通常用於將一個指定的文件打開爲一個預約的流:標準輸入,標準輸出或標準出錯。fdopen獲取一個現有的文件描述符,並使一個標準的IO流與該描述符相結合。此函數經常使用與由建立管道和網絡通訊函數返回的描述符,由於這些特殊類型的文件不能用標準IO fopen函數打開,因此咱們必須先調用設備專用函數獲取一個文件描述符,而後用fdopen使一個標準IO流與該描述符相關聯。

type參數指定對IO流的讀寫方式,詳細以下表(使用b,使得標準IO能夠區分文本文件和二進制文件)

  注意:對於fdopen,type的意義稍有不一樣,由於該描述符已經被打開,因此fdopen爲寫而打開並不截短該文件,另外也不能建立該文件。

對於讀寫類型打開一個文件時(圖中的+)

  1. 若是中間沒有fflush,fseek,fsetpos,frewind則在輸出的後面不能直接跟輸入
  2. 若是中間沒有fseek,setpos,rewind或一個輸入操做沒有到達文件尾端,輸入操做後不能跟輸出

總結一下上表的內容:

#include <stdio.h>
int fclose(FILE *fp);

  在該文件被關閉前,沖洗緩衝區中的輸出數據,緩衝區中的任何數據被丟棄,若是標準I/O庫自動爲流分配了一個緩衝區,則釋放此緩衝區。

  一個進程終止時(直接調用exit或從main中返回)全部帶爲寫緩衝數據的標準I/O流都被沖洗,全部打開的I標準/O流都被關閉。

 定位流

#include <stdio.h>
long ftell(FILE *fp);//成功返回當前文件位置,失敗返回-1L
int fseek(FILE *fp,long offset,int whence);//成功返回0失敗返回-1
void rewind(FILE *fp);//返回文件開頭
  1. 二進制文件當前位置:文件位置指示器指向文件的起始位置,以字節爲度量單位,ftell的返回值就是字節的位置。
  2. 文本文件當前位置:先將whence設置爲SEEK_SET,offset設置爲0或ftell返回值,而後調用ftell獲取

內存流

  使用第三方庫的時候,咱們須要處理某個文件,而這個文件不必定是從本地磁盤上讀取,多是分佈式文件系統或者其餘地方,而第三方庫的接口卻只提供了一個FILE *參數,意味着只能從磁盤加載,無法直接處理已經加載到內存的數據。這個時候,fmemopen就能夠派上用場了,將FILE對象映射到內存上,無需從磁盤上讀取。

#include <stdio.h>
FILE* fmemopen(void*buf, size_t size, const char* mode);
/*
1.不管什麼時候以追加方式打開內存流,當前文件位置設置爲緩衝區中的第一個NULL字節,若是緩衝區中不存在NULL字節,當前位置就設置爲緩衝
區結尾的最後一個字節,當流不是以追加方式打開時。當前位置設置爲緩衝區的開始位置,覺得追加模式經過第一個NULL字節肯定數據的尾端
不適合二進制數據(二進制數據在尾端以前可能包含多個NULL)
2.若是buf是一個null指針,打開流讀寫無心義,由於這種狀況緩衝是經過fmemopen分配的,沒有辦法找到緩衝區的地址,以只寫方式打開流
沒法讀入寫入的數據,已讀方式打開沒法讀取寫入緩衝區的數據
3.任什麼時候候只要增長緩衝區中的數據量以及調用fclose,fflush,fseek,fseeko,fsetpos都會在當前位置寫個null字符
*/
FILE* open_memstream(char**ptr, size_t* sizeloc);//面向字節

#include <wchar.h>
FILE* open_wmemstream(wchar_t** ptr, size_t* sizeloc);//面向寬字節
//以上函數成功返回流指針,失敗返回NULL

  fmemopen()函數打開一個內存流,使你能夠讀取或寫入由buf指定的緩衝區。其返回FILE*fp就是打開的內存流,雖然仍使用FILE指針進行訪問,但其實並無底層文件(並無磁盤上的實際文件,由於打開的內存流fp是在內存中的),全部的I/O都是經過在緩衝區與主存(就是內存)之間來回傳送字節來完成的。

後兩個與第一個區別

  1. 建立的流只能寫打開
  2. 不能指定本身的緩衝區,但能夠分別經過bufp和sizep參數訪問緩衝區地址和大小
  3. 關閉流後須要自行釋放緩衝區
  4. 對流添加字節會增長緩衝區大小

緩衝區地址和大小使用的原則:

  1.地址和長度只有調用fclose或fflush後纔有效。2.這些值只有在下一次流寫入或調用fclose前纔有效,由於緩衝區能夠增加,可能須要從新分配,若是出現這種狀況,緩衝區的地址在下一次調用fclose或fflush時纔會變。

  當用fclose()關閉流或用fflush()刷新流時,bufp和sizep被更新,以包含緩衝區的指針及其大小。只要沒有進一步的輸出流發生,這些值仍然有效。若是執行額外的輸出,必須再次刷新流來存儲新的值,才能再次使用它們。一個空字符被寫入緩衝區的末尾,但它存儲在sizep中的size值中不包括它。

  經過調用fmemopen()、open_memstream()或open_wmemstream()建立的一個與內存緩衝區相關聯的流的輸入和輸出操做,發生在內存緩衝區的範圍內,受限於實現。對於用open_memstream()或open_wmemstream()打開的流的狀況,內存區域動態增加,以適應必要的寫操做。對於輸出,在刷新或關閉操做期間,數據從函數setvbuf()提供的緩衝區移動到內存流。若是沒有足夠的內存來增加內存區域,或者操做須要訪問相關內存區域之外的地方,相關的操做失敗。由於避免了緩衝區溢出,內存流很是適用於建立字符串。由於內存流只訪問主存,不訪問磁盤上的文件,因此對於把標準I/O流做爲參數用於臨時文件的函數來講,會有很大的性能提高。

相關文章
相關標籤/搜索