2016-05-12 52 views
6

我是C++的初學者,並試圖更好地瞭解feof()。我讀過feof()標誌,只有在嘗試讀取文件末尾時纔會設置爲true,因此很多時候,初學者會比他們預期的多讀一次,如果他們執行的操作類似while(!feof(file))。我試圖理解的是,它是如何解釋爲什麼試圖讀取文件的末尾?整個文件是否已經讀入,字符的數量是已知的還是有一些其他機制在起作用?feof()如何知道文件何時到達?

我意識到這可能是一個重複的問題的地方,但我一直無法找到它,可能是因爲我不知道這個詞的最好方法就是我要問。如果有一個答案已經有一個鏈接將不勝感激。謝謝。

+0

http://stackoverflow.com/questions/4358728/end-of-file-eof-in-c希望這會有所幫助:) – kartik7153

+1

圖像流沒有已知的限制。然後,沒有其他方法可以嘗試讀取文件的結尾。 (注意文件流是不同類型輸入/輸出的抽象) –

+1

@ kartik7153不能回答他的問題。他詢問操作系統是如何特別決定文件何時到達的。 – Creris

回答

10

任何其他的C++庫做,最終還是從文件中讀取。在操作系統的某個地方,有一段代碼最終可以處理該讀取。它從文件系統獲得文件的長度,與文件系統存儲其他文件的方式相同。知道文件的長度,讀取的位置以及要讀取的字節數,可以確定低級別讀取結果是文件結尾。

當該確定時,它被傳遞堆棧。最終,它會到達內部記錄已到達文件末尾的標準庫。當讀入庫的請求試圖超過該錄製結束時,EOF標誌被設置並且feof將開始返回true。

+0

感謝這正是我想知道的! – Austin

8

feof()是緩衝 I/O標準C庫的一部分。由於它被緩衝,所以fread()預先讀取一些數據(當然,不是整個文件)。如果,當緩衝,fread()檢測EOF(底層操作系統例程返回特殊值,通常-1),它設置在FILE結構的標誌。 feof()只是檢查該標誌。所以feof()返回true基本上意味着「以前的讀取嘗試遇到文件結束」。

如何檢測 EOF是OS/FS特異性,並已完全與C庫/語言的任何事情。操作系統有一些接口可以從文件中讀取數據。 C庫只是操作系統和程序之間的橋樑,所以如果移動到另一個操作系統,則不必更改程序。操作系統知道文件如何存儲在文件系統中,因此它知道如何檢測EOF。我的猜測是,它通常是通過比較當前位置和文件長度來執行的,但它可能並不那麼容易,並且可能涉及很多低級細節(例如,如果文件位於網絡驅動器上?)。

一個有趣的問題是,當流是在年底會發生什麼,但尚未發現任何讀取。例如,如果你打開一個空文件。在fread()之前第一次撥打feof()是否返回true或false?答案可能是錯誤的。 The docs沒有在這個問題上非常明確:

這一指標通常是由以前的操作流上的 是試圖在或超過結束文件中讀取設置。

聽起來好像一個特定的實現可以選擇一些其他不尋常的方式來設置該標誌。

+0

謝謝。請您詳細說明一下,「如果緩衝時,fread()檢測到EOF」?我想知道的是EOF如何實際標記以及如何檢測。 – Austin

+0

@Jake,看我的編輯。 –

+0

非常感謝! – Austin

3

大多數文件系統維護有關文件(包括它的大小),並嘗試讀取過去在FEOF標誌被設置結果的結尾元信息。其他的,例如舊的或者輕量級的文件系統,當它們到達鏈中最後一個塊的最後一個字節時,會設置它。

+0

我認爲這是最接近我所問的。所以當你做'FILE * fp = fopen()'的時候,FILE類型已經知道了'feof()'可以使用的文件的大小了嗎? – Austin

+0

通常,是的。部分元信息是文件大小,(也有日期,位置,以前的版本等)。元信息與文件一起存儲,並在打開文件時檢索。但它實際上並不需要文件系統,所以它取決於它是如何實現的。 – Gregg

2

feof()實際上是如何知道文件結束的時間?

當代碼試圖讀取通過最後一個字符。

根據文件類型的不同,最後一個字符必須知道,直到嘗試讀取它過去並且沒有字符可用。


樣本代碼演示feof()打算從0到1個

#include <stdio.h> 

void ftest(int n) { 
    FILE *ostream = fopen("tmp.txt", "w"); 
    if (ostream) { 
    while (n--) { 
     fputc('x', ostream); 
    } 
    fclose(ostream); 
    } 
    FILE *istream = fopen("tmp.txt", "r"); 
    if (istream) { 
    char buf[10]; 
    printf("feof() %d\n", feof(istream)); 
    printf("fread %zu\n", fread(buf, 1, 10, istream)); 
    printf("feof() %d\n", feof(istream)); 
    printf("fread %zu\n", fread(buf, 1, 10, istream)); 
    printf("feof() %d\n", feof(istream)); 
    puts(""); 
    fclose(istream); 
    } 
} 

int main(void) { 
    ftest(9); 
    ftest(10); 
    return 0; 
} 

輸出

feof() 0 
fread 9 // 10 character read attempted, 9 were read 
feof() 1 // eof is set as previous read attempted to read passed the 9th or last char 
fread 0 
feof() 1 

feof() 0 
fread 10 // 10 character read attempted, 10 were read 
feof() 0 // eof is still clear as no attempt to read passed the 10th, last char 
fread 0 
feof() 1 
-2

feof()函數設置文件指示符的末尾時被讀出的EOF字符。所以當feof()讀取最後一項時,EOF首先不會被讀取。由於沒有設置EOF指示符並且feof()返回零,因此流再次進入while循環。這一次fgets開始知道下一個字符是EOF,它丟棄它並返回NULL,但也設置EOF指示符。因此feof()檢測到文件指示符的結束並返回一個非零值,因此打破了while循環。