¿Cómo leer un archivo de texto en crecimiento en C ++?

Intento leer un archivo que está creciendo (algo similar a lo que hace tail -F ), pero debe haber algunos problemas con mi código:

 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 pasa nada.

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

Me gustaría saber qué está mal en mi código, y si es realmente necesario cerrar y volver a abrir el mismo archivo para este propósito.

Gracias.

El ciclo es incorrecto, ya que cuando se encuentra tellg() devuelve -1 y no hay comprobación de eof() inmediatamente después de la llamada a getline() que debe haber. Cambiar bucle a:

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

Además, como p se declara como size_t cuando tellg() devuelve -1 el valor de p se estableció en 4294967295 . Esto significaba que seekg() se estaba configurando más allá del final del archivo. Cambia el tipo de p a std::streamoff y confirma que la llamada a seekg() fue exitosa:

 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 fin.

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

 #include  #include  #include  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; } 

Este método me ha funcionado fielmente:

 #include  #include  #include  #include  #include  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; } } 

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