2012-08-01 14 views
9

Próbuję odczytać z pliku, który rośnie (coś podobnego do tego, co tail -F robi), ale nie musi być pewne problemy z mojego kodu:Jak odczytać rosnący plik tekstowy w 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); 
} 

bez linii // * // * 1 i 2, plik dziennika jest poprawnie czytany do końca, ale jeśli dodane są nowe linie nic się nie dzieje.

Za pomocą seekg i tellg Próbuję zapisać aktualną pozycję końcową pliku, tak, że po ponownym otwarciu mogę przejść tam i przeczytać to, co zostało dodane.

Chciałbym wiedzieć, co jest nie tak w moim kodzie, a jeśli naprawdę konieczne jest zamknięcie i ponowne otwarcie tego samego pliku w tym celu.

Dziękuję.

Odpowiedz

12

Pętla jest błędna jak podczas eof() napotkaniu tellg() powraca -1 i nie ma wyboru dla eof() natychmiast po wywołaniu getline() który nie musi być. Zmiana pętli:

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

Dodatkowo, jak p jest zadeklarowana jako size_t gdy tellg() powrócić -1 wartość p był ustawiony 4294967295. Oznaczało to, że seekg() był ustawiony poza końcem pliku. Zmień typ p do std::streamoff i potwierdzić wywołanie seekg() był udany:

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

jeśli jest to naprawdę konieczne, aby zamknąć i ponownie otworzyć ten sam plik do tego celu.

Nie, to nie jest konieczne, ale trzeba clear() stan eof ze strumienia. Poniżej znajduje się alternatywą dla skorygowanej wersji pisał kodu:

#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

teraz działa poprawnie. Dziękuję Ci. – Pietro

+0

Zauważyłem, że jeśli utworzę obiekt ifstream w pętli, to działa, ale jeśli go utworzę na zewnątrz, to nie. Czy konieczne jest zamknięcie i ponowne otwarcie pliku, aby przeczytać, co zostało dodane do niego? – Pietro

+0

@Pietro, musisz wyczyścić stan "ifstream", wywołując 'ifs.clear()' przed następną próbą odczytu. W tym podejściu niepotrzebne jest użycie 'tellg()' i 'seekg()'. – hmjd

1

Ta metoda pracował wiernie dla mnie:

#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

Ten kod działa dla mnie:

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); 
    } 
} 
Powiązane problemy