2012-06-14 42 views
0

因爲從文件中的數據是這樣的,當:1號線名(倒數第一),下一行是得分(score1 2分.... score5)等等......所以我想,我需要爲函數getline的名字和對>>比分使用函數getline和閱讀>>文件C++

示例數據文件

David Beckham 
80 90 100 20 50 
Ronaldinho Gaucho 
99 80 100 20 60 
.... 

首先的,我有結構

struct Player { 
string name; 
int score[5]; 
} player[size] 

當從文件中讀取數據

int i = 0; 
while(!file.eof()) 
    { 
     for (int j = 0; j < 2; j++) //read each 2 two lines 
     {    
      if(j==0) // name 
      {    
       getline(file, player[i].name); 
      } 
         else if(j==1) // score 
      { 
       for(int k=0; k<5; k++) file >> player[i].grade[k]; 
      } 
       } 
     i++; //move to next player 
    } 

問題是閱讀後(第一玩家)的所有得分,好像不走下一行繼續讀取下一個名字,那種亂七八糟的在那裏。因此,任何建議來糾正我的代碼或新想法做到這一點?

回答

5

讀最後得分後,換行仍然坐在輸入緩衝區。你需要跳過這個。 ignore函數對此很有用。

getline(file, player[i].name); 
for (int k = 0; k < 5; ++k) 
    file >> player[i].grade[k]; 
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 

根據情況檢查錯誤。 >>運營商,getlineignore都返回流引用,您可以檢查成功或失敗。


沒有必要爲j循環,因爲每次迭代做了完全不同的事情。只要立即寫上j=0的情況下,然後j=1的情況下,然後擺脫循環,就像我上面的代碼。 (並且注意j在循環內永遠不會等於2,所以你的條件無論如何都是錯誤的。)

+0

是的,我想打字,這是如果(j == 1)未2.仍不確定我應該在file.ignore()的()中放入什麼?我只是使用file.ignore(),我已經看到它的工作。 –

+1

你爲什麼不確定該放什麼?我*顯示*你要放什麼。文檔告訴你參數的含義。通過不輸入任何內容,您將使用默認值,即只跳過一個字符。它只適用於你,因爲你足夠幸運,換行符會在你閱讀的最後一位數字後立即出現。我的代碼將跳過所有*額外的字符,在換行符後停止。第二個參數很重要,因爲默認值是EOF。 –

+0

因爲忽略(numeric_limits :: max(),'\ n')看起來非常難看,所以我試圖找出要放入這些參數中的內容,我不認爲只是按原樣使用它。再次感謝,它幫助了我很多。 –

1

你的主要問題是你直接從流中讀取>>的整數。這與從流中讀取字符串相結合是一個壞主意。讀取字符串將刪除新行,使用>>將不會刪除新行。

最好不要混合這兩種形式。總是使用>>或者總是使用getline()。注意:我不是最好說我最簡單。當你瞭解權衡以及如何彌補使用差異時,你可以一起使用它們。

因此,更容易將數字行讀入字符串,然後解析字符串。

std::string lineOfNumbers; 
std::getline(file, lineOfNumbers); 

// Now you have read all the numbers and the new line. 
std::stringstream streamOfNumbers(lineOfNumbers); 
while(streamOfNumbers >> value) 
{ 
    // Do something with number. 
} 

幾乎都是錯誤的使用方法:

while(!file.eof()) 

這是因爲EOF標誌沒有設置,直到你讀過去EOF。請注意,最後一次讀取將讀取到但不超過eof。因此即使沒有可用的數據,您也將進入循環。

標準模式是:

while(file >> object) 
{ 
    // Action 
} 

考慮到這一點我會定義一個代表所有你想要的(即兩行)的信息的類。一個簡單的版本將是

class TwoLineReader 
{ 
    public: 
    std::string line1; 
    std::string line2; 
}; 
std::istream& operator>>(std::istream& stream, TowLineReader& record) 
{ 
    std::getline(stream, record.line1); 
    std::getline(stream, record.line2); 
    return stream; 
} 

TowLineReader obj; 
while(file >> obj) 
{ 
    // Do stuff 
} 

這很好,如果你想要做的就是讀線。
但數據看起來像它有一個結構。所以我會構建一個表示數據的類,然後直接將數據讀入該結構。所以這更多的是我會做的。我也會用算法替換while()循環。

頁眉

#include <algorithm> 
#include <iterator> 
#include <fstream> 
#include <sstream> 
#include <string> 
#include <vector> 

/* 
* Example Data 

David Beckham 
80 90 100 20 50 
Ronaldinho Gaucho 
99 80 100 20 60 
*/ 

的類別:

class Player 
{ 
    std::string   name; 
    std::vector<int> goals; 

    // Stream operator that reads a platers name and his goals. 
    friend std::istream& operator>>(std::istream& stream, Player& record) 
    { 
     // Read the name 
     std::getline(stream, record.name); 

     // Read the line of goals. 
     // Copies the data into goals. 
     std::string scores; 
     std::getline(stream, scores); 

     // std::copy replaces a while loop that pushes each number into the vector. 
     std::stringstream scorestream(scores); 
     std::copy(std::istream_iterator<int>(scorestream), 
        std::istream_iterator<int>(), 
        std::back_inserter(record.goals)); 

     return stream; 
    } 
}; 

用法:

int main() 
{ 

    std::ifstream dataFile("data"); 
    std::vector<Player> players; 

    // Copy all players into a vetor 
    std::copy(std::istream_iterator<Player>(dataFile), 
       std::istream_iterator<Player>(), 
       std::back_inserter(players)); 
} 
+0

優秀的解釋! –