程式碼開啟 rb+ 模式,fread 讀取 20 位元組後,直接 fwrite 寫入失敗 (回傳 0),errno 為 0。
C 標準 (C11 §7.21.5.3) 規定:更新模式 (+) 下,輸入操作後不能直接進行輸出操作,反之亦然,必須中間插入定位操作 (fseek/fsetpos/rewind)。
這是因為檔案流內部維護單一緩衝區與位置指標,讀寫模式切換需刷新緩衝區並重新定位。
FILE* fp = fopen("aaa.txt", "rb+");
fread(buf, 20, 1, fp); // 讀取操作
fwrite("test", 5, 1, fp); // ❌ 直接寫入:未定義行為,通常失敗
FILE* fp = fopen("aaa.txt", "rb+");
fread(buf, 20, 1, fp); // 讀取
fseek(fp, 0, SEEK_CUR); // ✅ 關鍵:定位操作切換模式 (SEEK_CUR 保持當前位置)
fwrite("test", 5, 1, fp); // ✅ 現在可以正常寫入
// 或 fseek(fp, 0, SEEK_SET); // 回到檔案開頭
// 或 fseek(fp, 0, SEEK_END); // 移至檔案結尾
經驗顯示:必須使用 SEEK_SET 或 SEEK_END,SEEK_CUR 可能不觸發模式切換 (視 libc 實作而定)。最保險做法:
// 讀取後要寫入
fseek(fp, 0, SEEK_SET); // 或當前位置 ftell 後 SEEK_SET
// 寫入後要讀取
fseek(fp, 0, SEEK_SET);
#define _CRT_SECURE_NO_WARNINGS
#include
int main() {
FILE* fp = fopen("aaa.txt", "rb+");
if (!fp) return 1;
// 移至檔案結尾取得大小
if (_fseeki64(fp, 0, SEEK_END) != 0) { fclose(fp); return 1; }
long long size = _ftelli64(fp);
if (size < 0) { fclose(fp); return 1; }
if (_fseeki64(fp, 0, SEEK_SET) != 0) { fclose(fp); return 1; }
char buf[1024];
if (fread(buf, 20, 1, fp) != 1) { fclose(fp); return 1; }
// 關鍵修正:fread 後必須 fseek 才能 fwrite
if (fseek(fp, 0, SEEK_SET) != 0) { fclose(fp); return 1; } // 或 SEEK_CUR (視實作)
if (fwrite("test", 5, 1, fp) != 1) {
printf("fwrite 失敗\n");
fclose(fp);
return 1;
}
fclose(fp);
printf("成功\n");
return 0;
}
C11 7.21.5.3/7: "When a file is opened with update mode ('+' as the second or third character in the mode argument), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function."
rb+/wb+/ab+ 更新模式下,讀寫切換強制需 fseek/fflush/rewinderrno 不一定會設定,行為屬未定義,難以除錯fseek(fp, 0, SEEK_SET) 確保行為一致std::fstream,RAII 管理、型別安全、避免此類陷阱