對於標準I/O都是圍繞流進行操做,當用標準I/O庫打開一個文件時,使一個流與一個文件相關聯。網絡
流的定向決定了所讀寫的字符是單個字節仍是多字節。當流建立時並無定向,若在未定向的流上使用一個多字節I/O函數,則流設置爲寬定向,若使用單字節函數,流定向爲字節定向。分佈式
FILE一般是一個結構,它包含了標準I/O庫管理流所需的信息:用於實際I/O文件的描述符,指向流緩衝區的指針,緩衝區長度,當前緩衝區的字符數以及出錯標誌。函數
標準IO流操做讀寫普通文件是使用全緩衝的,默認緩衝區長度是該文件系統優先選用的IO長度(從stat結構獲得的st_blksize值)性能
沖洗:說明標準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
強制沖洗緩衝
#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爲寫而打開並不截短該文件,另外也不能建立該文件。
對於讀寫類型打開一個文件時(圖中的+)
總結一下上表的內容:
#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);//返回文件開頭
使用第三方庫的時候,咱們須要處理某個文件,而這個文件不必定是從本地磁盤上讀取,多是分佈式文件系統或者其餘地方,而第三方庫的接口卻只提供了一個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.地址和長度只有調用fclose或fflush後纔有效。2.這些值只有在下一次流寫入或調用fclose前纔有效,由於緩衝區能夠增加,可能須要從新分配,若是出現這種狀況,緩衝區的地址在下一次調用fclose或fflush時纔會變。
當用fclose()關閉流或用fflush()刷新流時,bufp和sizep被更新,以包含緩衝區的指針及其大小。只要沒有進一步的輸出流發生,這些值仍然有效。若是執行額外的輸出,必須再次刷新流來存儲新的值,才能再次使用它們。一個空字符被寫入緩衝區的末尾,但它存儲在sizep中的size值中不包括它。
經過調用fmemopen()、open_memstream()或open_wmemstream()建立的一個與內存緩衝區相關聯的流的輸入和輸出操做,發生在內存緩衝區的範圍內,受限於實現。對於用open_memstream()或open_wmemstream()打開的流的狀況,內存區域動態增加,以適應必要的寫操做。對於輸出,在刷新或關閉操做期間,數據從函數setvbuf()提供的緩衝區移動到內存流。若是沒有足夠的內存來增加內存區域,或者操做須要訪問相關內存區域之外的地方,相關的操做失敗。由於避免了緩衝區溢出,內存流很是適用於建立字符串。由於內存流只訪問主存,不訪問磁盤上的文件,因此對於把標準I/O流做爲參數用於臨時文件的函數來講,會有很大的性能提高。