一、什么是標準 I/O?(FILE* 接口)
標準 I/O 是 C 標準庫為我們提供的一套高級文件操作接口,核心基于結構體 FILE,常見函數如:
-
fopen() / fclose()
-
fread() / fwrite()
-
fprintf() / fscanf()
-
fflush() / fseek() / ftell()
其背后的設計理念是:在用戶空間加一層緩沖區機制,減少頻繁的系統調用,提高 I/O 效率。
二、標準流與 FILE* 指針的關系
C 語言啟動時自動打開的三個標準流:
名稱 | 全局變量 | 描述 | 默認綁定設備 |
---|---|---|---|
標準輸入 | stdin | 鍵盤輸入 | 文件描述符 0 |
標準輸出 | stdout | 屏幕輸出 | 文件描述符 1 |
標準錯誤輸出 | stderr | 屏幕錯誤輸出 | 文件描述符 2 |
它們本質上是三個全局變量指針:
extern FILE *stdin; // 標準輸入
extern FILE *stdout; // 標準輸出
extern FILE *stderr; // 標準錯誤
FILE 的結構體對象,這些對象在程序啟動時已經初始化好,不需要手動打開。
三、標準 I/O 的緩沖機制分類
標準 I/O 相比 read()/write() 的一個顯著特點是:內部使用了緩沖區機制(緩解頻繁的系統調用)。
1. 無緩沖(Unbuffered)
-
直接寫入/讀取,不做緩存。
-
特征:每次 fputc()、fprintf(stderr, ...) 都是一次系統調用。
-
示例:標準錯誤流 stderr 通常是無緩沖。
2. 行緩沖(Line Buffered)
-
讀寫一整行再提交,或者滿足以下任一條件立即刷新:
-
遇到換行符 \n
-
調用 fflush()
-
緩沖區被填滿
-
程序正常退出
-
示例:標準輸出 stdout 在連接終端時通常是行緩沖。
3. 全緩沖(Fully Buffered)
-
只有當緩沖區滿時或顯示調用 fflush() 時才進行 I/O 操作。
-
示例:對磁盤文件操作通常是全緩沖。
關于緩沖區的大小
標準 I/O 緩沖區大小(來自 APUE 的描述)
標準 I/O 使用的是 用戶空間的緩沖機制,而這部分緩沖區的大小通常為:
? BUFSIZ,大小通常是 8192 字節(即 8KB)
-
BUFSIZ 是一個宏,定義在 <stdio.h> 中,表示標準庫默認的緩沖區大小。
-
實際大小由系統實現決定,但大多數現代系統中是 8192 字節(8KB)。
-
你可以通過下面代碼查看具體大小:
#include <stdio.h> int main() { printf("BUFSIZ = %d\n", BUFSIZ); return0; }
🧠 說明一下:
-
標準I/O函數(如 fopen/fread/fwrite)使用內部緩沖區,提高讀寫效率。
-
這個緩沖區由 libc 實現,屬于用戶空間。
-
不像 read() / write() 系統調用直接進入內核空間,標準IO通過一次性讀寫大塊內容來減少系統調用次數。
🧪 補充說明:你還可以自己設定緩沖區
FILE *fp = fopen("file.txt", "r"); char buf[BUFSIZ]; setbuf(fp, buf); // 手動設置緩沖區
或者使用 setvbuf() 函數精細控制緩沖類型(全緩沖、行緩沖、無緩沖)和大小。
📝 總結
名稱 | 值(常見) | 定義位置 | 用途 |
---|---|---|---|
BUFSIZ | 8192 字節 | <stdio.h> | 標準I/O默認緩沖區大小 |
📌 注意:BUFSIZ 是用于標準IO緩沖(如 fopen),而不是 read() 等系統調用(后者不涉及標準IO緩沖機制)。
這里FILE結構體需要描述
FILE 結構體的典型定義(簡化版)
FILE 的真實定義是不公開的(屬于 libc 實現細節),但你可以在 GNU libc 或 musl 的源碼中看到類似的簡化結構:
typedef struct _IO_FILE { int _fileno; // 文件描述符,對應 open 返回的 int char *_buffer; // 指向緩沖區的指針 char *_bufpos; // 當前緩沖位置 char *_bufend; // 緩沖區末尾 int _flags; // 文件狀態,如可讀、可寫、錯誤、EOF 等 long _pos; // 當前文件位置(用于 ftell、fseek) // 還有更多復雜字段... } FILE;
📌注意:不同系統實現(如 glibc、musl)中,這個結構體的字段名稱和結構會有所不同。
🎯 FILE 和底層文件描述符的區別
項目 | FILE(高級IO) | 文件描述符(低級IO) |
---|---|---|
類型 | FILE *(結構體指針) | int(整數) |
接口 | fopen, fread, fwrite 等 | open, read, write 等 |
是否緩沖 | ? 有緩沖區(提高效率) | ? 無緩沖(每次都直接系統調用) |
是否格式化支持 | ? fprintf, fscanf | ? 不支持格式化 |
🧠 標準流的 FILE 示例
C語言一開始默認打開了三個標準流(在 <stdio.h> 中定義):
extern FILE *stdin; // 標準輸入 extern FILE *stdout; // 標準輸出 extern FILE *stderr; // 標準錯誤
你可以直接使用這些來讀寫數據:
fprintf(stdout, "Hello\n"); fscanf(stdin, "%d", &num);
🧪 進階:緩沖機制與 FILE
-
FILE 內部包含了一個緩沖區,默認大小是 BUFSIZ(通常是 8192 字節)。
-
分為:
-
全緩沖(默認情況,大文件使用)
-
行緩沖(用于終端)
-
無緩沖(stderr)
你可以用 setvbuf() 或 setbuf() 控制緩沖方式。