檔案與輸入輸出

檔案結尾(EOF)

/ EOF -> EE-oh-EFF /

你一頁一頁地讀一疊紙。終於,你伸手去拿下一頁,卻沒有下一頁了——你碰到了這疊紙的底。檔案結尾正是那個時刻:沒有更多資料可讀了,而你需要一個清楚、可靠的訊號,好讓你知道該停下,而不是永遠空轉。

具體來說,EOF 不是存在檔案裡的某個特殊位元組——它是讀取介面回報的一種狀況。在原始層,read(fd, buf, n) 回傳 0 即表示檔案結尾:讀到零個位元組,且不會再有了。(回傳 -1 是錯誤,那不一樣;0 專指 EOF。)所以標準迴圈就讀到 read() 回傳 0 為止。在緩衝的 stdio 層,像 fgetc() 這樣的函式會回傳特殊值 EOF(一個巨集,慣例上是 -1,這正是為什麼 fgetc 回傳 int 而非 char——好讓它能同時承載 0 到 255 每個可能的位元組,以及那個不同的 EOF 標記)。串流碰到檔案結尾後,你可以用 feof(stream) 確認,但要注意 feof 回報的是過去事件——它只有在一次讀取已經拿不到資料之後才變真,所以你要在讀取之後檢查它、絕不在之前,否則就有多跑一次無效迴圈的風險。

為何重要:正確地偵測 EOF,正是「能處理完整個檔案的迴圈」與「永遠跑不完或早一項就停下的迴圈」之間的分野。經典的初學者臭蟲是把 feof() 放在迴圈頂端當條件——while (!feof(f))——這會多讀一次,因為 feof 只在失敗的讀取之後才翻轉。穩健的模式是讓讀取本身當測試:只要 fgetc 回傳的不是 EOF 就繼續,或只要 read 回傳大於 0 就繼續。

int c; while ((c = fgetc(f)) != EOF) { putchar(c); /* 處理一個位元組 */ } /* 迴圈正好在沒有更多資料時結束——不會多跑一次 */

讓讀取本身當測試。fgetc 回傳 int,使得 EOF(-1)不會跟任何真實位元組相撞。

EOF 是一種狀況,不是檔案裡的某個位元組。read() 回傳 0 是 EOF;回傳 -1 是錯誤——把它們分清楚。而且不要用 while (!feof(f)) 來迴圈:feof 回報的是一次已過去的失敗讀取,所以它會多跑一次迴圈本體。直接測試讀取的結果。

又稱
end of fileend-of-input檔案結尾輸入結尾