2014-12-03 70 views
1

我在理解C++中的文件輸入流時感到很掙扎。我有一個代碼片段如下:ifstream.eof()在C++中沒有評估爲true

#include <iostream> 
#include <fstream> 
#include <string> 

using namespace std; 

int main() { 
    ifstream in("x.txt"); 

    bool done = false; 
    do { 
     string input = ""; 
     getline(in,input); 
     int x1; 
     int x2; 
     in >> x1; 
     in >> x2; 
     cout << input << " " << x1 << " " << x2 << endl; 
     in.ignore(); 
     if(in.eof()) { 
      done = true; 
      cout << "reached eof" << endl; 
     } 
    } while(!done); 

    return 0; 
} 

隨着文件x.txt閱讀如下

task1 
12 
1313 
task2 
13 
1414 
[blank line] 

注意在輸入文件的末尾故意包含空行的。所有這一切意味着輸入「1414」後按下了輸入/返回鍵。

我的預期輸出是

task1 12 1313 
task2 13 1414 
reached eof 

但實際上,輸出

task1 12 1313 
task2 13 1414 
13 1414 
reached eof 

我明白,按enter內的輸入文件生成一個隱換行符,並使用像一個語句之前getline(ifstream, string)我們應該ignore()那下一個換行符。這就是說,爲什麼ifstream.eof()沒有評估爲真,即使在'1414'之後的隱含換行符是ignore()

+3

'而(在X1 >> >> X2)' – Borgleader 2014-12-03 15:31:33

+1

你爲什麼不測試的返回值'getline'? 'in >> x1'和'in >> x2'同樣的問題?如果您有問題,我/ O **檢查I/O工作** – 2014-12-03 15:32:29

+0

這基本上是http://stackoverflow.com/q/5605125/981959具有不同(但仍然是錯誤的)環 – 2014-12-03 15:34:45

回答

2

eof標誌在您嘗試讀取超出文件末尾之前未設置。而應該檢查結果從流中讀取,或許像

while (getline(in, input) && in >> x1 >> x2) { 
    cout << input << " " << x1 << " " << x2 << endl; 
    in.ignore(); 
} 
cout << "reached eof" << endl; 
+0

重複他也許應該忽略,直到''\ n''爲好,以防萬一出現在該行的末尾多餘的空白。 – 2014-12-03 15:52:10

0

在第二循環流的位置是在年底結束後,但不會設置eofbit,直到您嘗試讀取更多的數據。讓我們考慮前兩個循環已經運行後會發生什麼,你進入第三次循環:

您嘗試讀取一行:

getline(in,input); 

該讀什麼,因爲你已經到達了流的末尾,所以它設置eofbit,因爲沒有提取也設置failbit。但是你不檢查一個線被讀取,或者如果input非空,你只是盲目地繼續

你聲明瞭兩個未初始化的變量:

int x1; 
    int x2; 

然後再次嘗試閱讀:

in >> x1; 
    in >> x2; 

這甚至不嘗試讀取任何東西,因爲failbit已經設置,但你不要在這裏檢查它。 x1x2保持不變並保持未初始化。

然後你打印出來的未初始化的整數,這恰好從以前循環打印出來的值,因爲這就是恰好是在棧上:

cout << input << " " << x1 << " " << x2 << endl; 

這什麼也不做,因爲failbit設置:

in.ignore(); 

現在最後您檢查流狀態,但它來得太遲,以防止上面的所有問題:

if(in.eof()) { 

您應該檢查I/O操作是否成功,而不是假設他們這樣做,然後在很晚的時候發現他們有什麼問題,但是現在爲時已晚。

檢查I/O操作的方法是在布爾上下文中測試流, if (in),你應該是檢查EOF因爲不被設置,直到你到達流的末尾,然後嘗試讀取再次

小李的回答顯示了正確的方式做到這一點,但你也應該閱讀Why is iostream::eof inside a loop condition considered wrong?

+0

如果他已經提取的文件的最後一個字符(與'ignore'),那麼'eofbit'和'failbit'應該在'getline'進行設置,在'在>> x1'之前達到。 – 2014-12-03 15:54:22

+0

@JamesKanze,嗯,是的,我錯誤地忽略了忽略:)我確實提到過,當'failbit'設置時它甚至不會嘗試做任何事情,我會更清楚地說明 – 2014-12-03 15:55:20