2012-08-01 15 views
9

Sto cercando di leggere da un file che sta crescendo (qualcosa di simile a quello che tail -F fa), ma ci deve essere qualche problema con il mio codice:Come leggere un file di testo in crescita 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); 
} 

senza le linee // * 1 e // * 2, il file di registro viene letto correttamente fino alla fine, ma se vengono aggiunte nuove righe non accade nulla.

Con seekg e tellg Sto tentando di memorizzare la posizione finale corrente del file, in modo che quando lo riaprio riesca ad andare lì e leggere ciò che è stato aggiunto.

Mi piacerebbe sapere cosa c'è di sbagliato nel mio codice e se è veramente necessario chiudere e riaprire lo stesso file per questo scopo.

Grazie.

risposta

12

Il ciclo non è corretto, come quando si incontra eof()tellg() rendimenti -1 e non v'è alcun controllo per eof() subito dopo la chiamata a getline() che ci deve essere. Cambio loop:

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

Inoltre, come p è dichiarata come size_t quando tellg() ritorno -1 il valore di p veniva impostato su 4294967295. Ciò significava che seekg() era impostato oltre la fine del file. Cambiare il tipo di p per std::streamoff e confermare la chiamata a seekg() ha avuto successo:

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

se è veramente necessario chiudere e riaprire la stessa lima per questo scopo.

No, non è necessario, ma è necessario clear() stato eof dal flusso. Di seguito è un'alternativa a una versione corretta del codice scritto:

#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

Ora sta funzionando correttamente. Grazie. – Pietro

+0

Ho notato che se creo l'oggetto ifstream nel ciclo funziona, ma se lo creo all'esterno non lo fa. È necessario chiudere e riaprire un file per leggere cosa è stato aggiunto ad esso? – Pietro

+0

@Pietro, è necessario cancellare lo stato eof di 'ifstream' chiamando' ifs.clear() 'prima del successivo tentativo di lettura. Io penso che 'tellg()' e 'seekg()' non saranno necessari con questo approccio. – hmjd

1

Questo metodo ha funzionato fedelmente per me:

#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

Questo codice funziona per me:

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); 
    } 
}