fopen的「+」模式(r+/w+/a+)均支持讀寫,但初始光標位置、文件截斷行為、寫入覆蓋邏輯存在關鍵差異。本文通過實測總結核心區別,附帶避坑指南。
| 模式 | 文件存在性 | 初始光標 | 文件內容 | 寫入行為 | 讀取行為 |
|---|---|---|---|---|---|
| r+ | 必須存在 | 文件開頭(0) | 保留 | 從開頭覆蓋 | 正常讀取,光標移動 |
| w+ | 不存在則創建 | 文件開頭(0) | 清空(截斷為0) | 從開頭寫入(新內容) | 可讀(但通常無內容) |
| a+ | 不存在則創建 | 文件結尾(EOF) | 保留 | 只能追加(光標強制尾部) | 光標自動回開頭讀取 |
FILE *fp = fopen("test.txt", "r+");
// 文件必須存在,否則返回NULL
// 光標位置:0
fprintf(fp, "NEW"); // 覆蓋前3字節
// 文件長度不變,除非寫入超過原長度
適用場景:原地修改文件部分內容(如修改配置文件特定字段)。
風險:誤以為是追加,實際覆蓋開頭數據。
FILE *fp = fopen("test.txt", "w+");
// 文件不存在 → 創建
// 文件存在 → 長度截斷為0(內容清空!)
// 光標位置:0
fprintf(fp, "HELLO"); // 寫入新內容
rewind(fp); // 回到開頭
char buf[100];
fgets(buf, sizeof(buf), fp); // 可讀回剛寫內容
適用場景:生成臨時文件、完全重寫配置文件。
致命陷阱:打開瞬間原內容永久丟失,無法恢復。
FILE *fp = fopen("test.txt", "a+");
// 文件不存在 → 創建
// 文件存在 → 保留內容
// 光標位置:文件結尾(EOF)
fprintf(fp, "APPEND"); // 追加到末尾
// 關鍵特性:寫入前系統強制將光標移至EOF,fseek/rewind無效!
rewind(fp); // 可移動光標讀取
fgets(buf, sizeof(buf), fp); // 正常讀取全文
關鍵行為:任何寫入操作前,內核強制將文件偏移量設置為文件末尾,這是POSIX標準要求,fseek、rewind對寫入無效。
適用場景:日誌文件、數據追加記錄、多進程安全追加(配合O_APPEND)。
#include
#include
void test_mode(const char* mode, const char* init_content, const char* write_str) {
FILE *fp = fopen("test.txt", "w");
if(init_content) fputs(init_content, fp);
fclose(fp);
fp = fopen("test.txt", mode);
if(!fp) { printf("%s: open failed\n", mode); return; }
// 嘗試讀取
char read_buf[100] = {0};
fgets(read_buf, sizeof(read_buf), fp);
printf("%s: read='%s'\n", mode, read_buf);
// 寫入
fputs(write_str, fp);
fclose(fp);
// 查看最終內容
fp = fopen("test.txt", "r");
fgets(read_buf, sizeof(read_buf), fp);
printf("%s: final='%s'\n\n", mode, read_buf);
fclose(fp);
}
int main() {
test_mode("r+", "ORIGINAL", "NEW"); // 覆蓋開頭
test_mode("w+", "ORIGINAL", "NEW"); // 清空後寫入
test_mode("a+", "ORIGINAL", "NEW"); // 追加到末尾
return 0;
}
r+: read='ORIGINAL'
r+: final='NEWIGINAL' // 覆蓋前3字符
w+: read='' // 文件被清空
w+: final='NEW' // 全新內容
a+: read='ORIGINAL'
a+: final='ORIGINALNEW' // 追加到末尾
\n↔\r\n轉換,影響ftell精度"rb+"、"wb+"、"ab+",無轉換,ftell返回真實字節偏移b標志"r" / "rb""w" / "wb"(確認無需舊數據)"a" / "ab"(日誌、流數據)"r+" / "rb+"(需精確控制偏移)"w+" / "wb+"(臨時文件、配置重生成)"a+" / "ab+"(讀取歷史、追加新數據)open(..., O_APPEND | O_WRONLY) + fdopen,內核級原子追加「+」賦予讀寫雙權,但初始光標、截斷行為、寫入語義由基礎模式(r/w/a)決定。牢記:r+改頭、w+換心、a+接尾,選對模式是數據安全的第一道防線。