FILE* fp = fopen("test.txt", "r+");
char buf[256] = {0};
size_t n = fread(buf, 1, 10, fp); // 讀 10 字節
// 處理 buf...
// fseek(fp, -10, SEEK_CUR); // 關鍵行:被註釋掉
fwrite(buf, 1, n, fp); // 返回 n,但文件未變!
現象:fread 和 fwrite 均返回成功,ferror 為 0,但打開文件發現內容未更新。
C99 §7.19.5.3/6:在輸入操作後進行輸出操作,或輸出後進行輸入,必須中間插入文件定位操作(
fseek/fsetpos/rewind),除非輸入操作遇到 EOF。
原因:FILE 結構體內維護單一緩衝區與狀態標誌(_IOREAD/_IOWRITE)。切換方向需沖刷緩衝區、重置指針、更新標誌,fseek 正是觸發此狀態機切換的標準動作。
// 讀 → 寫
fread(buf, 1, n, fp);
fseek(fp, -n, SEEK_CUR); // 回到讀取起始位置
fwrite(buf, 1, n, fp);
// 寫 → 讀
fwrite(buf, 1, n, fp);
fseek(fp, -n, SEEK_CUR); // 或 fflush(fp); fseek(fp, 0, SEEK_CUR);
fread(buf, 1, n, fp);
fflush 只沖刷輸出緩衝區,不重置讀寫狀態標誌,後續 fread 仍會讀到舊緩衝區數據或失敗。fseek(fp, 0, SEEK_CUR))。std::fstream 內部自動處理狀態切換,或用 std::filebuf 手動 pubseekoff。std::fstream fs("test.bin", std::ios::in | std::ios::out | std::ios::binary);
fs.read(buf, 10);
// fs.seekg(-10, std::ios::cur); // 必須 seekg/seekp 同步雙向指針
fs.write(buf, 10);
std::fstream 維護獨立的 get pointer (gptr) 和 put pointer (pptr),切換讀寫必須同步兩者,seekg/seekp 即可。