2012-08-01 28 views
9

estoy tratando de leer de un archivo que está creciendo (algo similar a lo que hace tail -F), pero debe haber algunos problemas con mi código:¿Cómo leer un archivo de texto en crecimiento en 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); 
} 

Sin las líneas // * // * 1 y 2, el archivo de registro se lee correctamente hasta el final, pero si se agregan nuevas líneas no sucede nada.

Con seekg y tellg Estoy tratando de almacenar la posición final actual del archivo, para que cuando lo vuelva a abrir pueda ir allí y leer lo que se ha agregado.

Me gustaría saber qué hay de malo en mi código, y si realmente es necesario cerrar y volver a abrir el mismo archivo para este fin.

Gracias.

Respuesta

12

El bucle es incorrecto, ya que cuando se encuentra eof()tellg() vuelve -1 y no hay ninguna verificación de eof() inmediatamente después de la llamada a getline() la que es necesario que haya. Cambio bucle para:

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

Además, como p está declarada como una size_t cuando tellg() volver -1 el valor de p se estaba estableciendo a 4294967295. Esto significaba que el seekg() se estaba configurando más allá del final del archivo. Cambiar el tipo de p a std::streamoff y confirme la llamada a seekg() tuvo éxito:

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

si es realmente necesario cerrar y volver a abrir el mismo archivo para este propósito.

No, no es necesario pero hay que clear() el estado eof de la corriente. La siguiente es una alternativa a una versión corregida del código publicado:

#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

Ahora funciona correctamente Gracias. – Pietro

+0

Observé que si creo el objeto ifstream en el bucle, funciona, pero si lo creo afuera no funciona. ¿Es necesario cerrar y volver a abrir un archivo para leer lo que se ha agregado? – Pietro

+0

@Pietro, debe borrar el estado eof del 'ifstream' llamando a' ifs.clear() 'antes del siguiente intento de lectura. Creo que el 'tellg()' y 'seekg()' serán innecesarios con este enfoque. – hmjd

1

Este método ha trabajado fielmente por mí:

#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

Este código funciona para mí:

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