2012-08-01 15 views
9

Ich versuche, aus einer Datei zu lesen, die (etwas Ähnliches, was tail -F tut) wächst, aber es muss einige Probleme mit meinem Code sein:Wie liest man eine wachsende Textdatei in C++?

string log, logFile("test.log"); 
size_t p = 0; 

while(true) 
{ 
    ifstream ifs(logFile.c_str()); 

    ifs.seekg(p); //*1 

    while(ifs.eof() == false) 
    { 
     getline(ifs, log); 

     cout << log << endl; 

     p = ifs.tellg(); //*2 
    } 

    nanosleep(&pause, NULL); 
} 

Ohne die Linien // * 1 und // * 2, die Protokolldatei wird korrekt bis zum Ende gelesen, aber wenn neue Zeilen hinzugefügt werden, passiert nichts.

Mit seekg und tellg Ich versuche, die aktuelle Endposition der Datei zu speichern, so dass, wenn ich es wieder öffnen ich dort Straße gehen und lesen, was hinzugefügt wurde.

Ich mag würde wissen, was in meinem Code falsch ist, und wenn es wirklich notwendig, die gleiche Datei für diesen Zweck zu schließen und wieder öffnen.

Vielen Dank.

Antwort

12

Die Schleife ist falsch, wie wenn eof() angetroffen wird tellg() kehrt -1 und es gibt keine Überprüfung auf eof() sofort nach dem Aufruf getline(), die sein muss, da. Ändern Schleife:

while (getline(ifs, log)) 
{ 
    cout << log << endl; 
    p = ifs.tellg(); 
} 

Zusätzlich wird, wie p als size_t erklärt, wenn tellg()-1 der Wert p Rückkehr wurde auf 4294967295 gesetzt wird. Dies bedeutete, dass die seekg() über das Ende der Datei hinaus eingestellt wurde. Ändern Sie den Typ von p zu std::streamoff und bestätigen Sie den Aufruf seekg() erfolgreich war:

if (ifs.seekg(p)) 
{ 
    while (getline(ifs, log)) 
    { 
     cout << log << endl; 
     p = ifs.tellg(); 
    } 
} 

, wenn es wirklich notwendig ist, zu schließen und erneut öffnen die gleiche Datei für diesen Zweck.

Nein, ist es nicht notwendig, aber Sie müssen den eof Zustand aus dem Strom clear(). Im Folgenden ist eine Alternative zu einer korrigierten Version des entsandten Code:

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

int main() 
{ 
    std::ifstream ifs("test.log"); 

    if (ifs.is_open()) 
    { 
     std::string line; 
     while (true) 
     { 
      while (std::getline(ifs, line)) std::cout << line << "\n"; 
      if (!ifs.eof()) break; // Ensure end of read was EOF. 
      ifs.clear(); 

      // You may want a sleep in here to avoid 
      // being a CPU hog. 
     } 
    } 

    return 0; 
} 
+0

it Now funktioniert einwandfrei. Vielen Dank. – Pietro

+0

Ich habe festgestellt, dass wenn ich das Ifstream-Objekt in die Schleife erstellen, es funktioniert, aber wenn ich es außerhalb erstellen, tut es nicht. Ist es notwendig, eine Datei zu schließen und erneut zu öffnen, um zu lesen, was ihr hinzugefügt wurde? – Pietro

+0

@Pietro, müssen Sie den eof-Zustand des 'ifstream' löschen, indem Sie' ifs.clear() 'vor dem nächsten Leseversuch aufrufen. I _think_ Die 'tellg()' und 'seekg()' sind bei diesem Ansatz unnötig. – hmjd

1

Diese Methode treu für mich gearbeitet hat:

#include <string> 
#include <chrono> 
#include <thread> 
#include <fstream> 
#include <iostream> 

int main(int, char* argv[]) 
{ 
    // open file passed in on command line (at end of file) 
    std::ifstream ifs(argv[1], std::ios::ate); 

    if(!ifs.is_open()) 
    { 
     std::cerr << "ERROR: opening log file: " << argv[1] << '\n'; 
     return 1; 
    } 

    // remember file position 
    std::ios::streampos gpos = ifs.tellg(); 

    std::string line; 
    bool done = false; 

    while(!done) 
    { 
     // try to read line 
     if(!std::getline(ifs, line) || ifs.eof()) 
     { 
      // if we fail, clear stream, return to beginning of line 
      ifs.clear(); 
      ifs.seekg(gpos); 

      // and wait to try again 
      std::this_thread::sleep_for(std::chrono::milliseconds(100)); 
      continue; 
     } 

     // remember the position of the next line in case 
     // the next read fails 
     gpos = ifs.tellg(); 

     // process line here 
     std::cout << "line: " << line << std::endl; 
    } 
} 
0

Dieser Code funktioniert für mich:

struct timespec pause; 
pause.tv_sec = 1; 
pause.tv_nsec = 0; 

std::ifstream ifs("test.log"); 
std::streamoff p; 

if(ifs.is_open()) 
{ 
    std::string line; 

    while(true) 
    { 
     if(ifs.seekg(p)) 
     { 
      while(std::getline(ifs, line)) 
      { 
       std::cout << line << std::endl; 
       p = ifs.tellg(); 
      } 
     } 

     ifs.clear(); 

     nanosleep(&pause, NULL); 
    } 
}