2010-04-23 22 views
14

Quiero crear un código pequeño en C++ con la misma funcionalidad que "tail-f": observe las nuevas líneas en un archivo de texto y muéstrelas en el resultado estándar.Implementar "tail -f" en C++

La idea es tener un hilo conductor que supervisa el archivo de

¿Hay una manera fácil de hacerlo sin abrir y cerrar el archivo cada vez?

+0

Es posible que tenga dificultades para hacer esto en C++ puro . Deberá usar alguna API específica de la plataforma. (Para empezar, no creo que pueda abrir un archivo en C++ de forma no exclusiva.) – sbi

+1

@sbi No creo que el estándar C++ tenga algo que decir sobre exclusividad. –

+1

¿Hay alguna razón por la que no puedas usar tail -f? –

Respuesta

11

Siga leyendo el archivo. Si la lectura falla, no haga nada. No hay necesidad de abrirlo y cerrarlo repetidamente. Sin embargo, le resultará mucho más eficiente utilizar funciones específicas del sistema operativo para monitorear el archivo, en caso de que su sistema operativo lo proporcione.

+2

+1: Tratar de leer hasta el final del archivo desde donde llegaste hasta ahora (para un archivo de longitud razonable) una vez por segundo es bastante barato en la práctica. Acabas de leer hasta que llegas al final, luego duermes por un segundo y vuelves a leer. (Si está en Windows, tenga cuidado de abrir con las banderas de compartir correctas para que no bloquee a otros escritores. Eso probablemente signifique usar las llamadas de IO nativas en lugar de las estándar de C++ ...) –

11

Eche un vistazo a inotify en Linux o kqueue en Mac OS.

Inotify es subsistema del kernel de Linux que permite suscribirse a los eventos en los archivos y que le informe a su aplicación cuando el aun sucedió en su archivo.

+0

Windows tiene un API equivalente para enviar notificaciones cuando un archivo cambia. –

1

He leído esto en one of Perl manuals, pero se traduce fácilmente en la norma C, que, a su vez, se puede traducir a istream s.

seek FILEHANDLE,POSITION,WHENCE 
     Sets FILEHANDLE's position, just like the "fseek" call of 
     "stdio". 
     <...> 
     A WHENCE of 1 ("SEEK_CUR") is useful for not moving the file 
     position: 

      seek(TEST,0,1); 

     This is also useful for applications emulating "tail -f". Once 
     you hit EOF on your read, and then sleep for a while, you might 
     have to stick in a seek() to reset things. The "seek" doesn't 
     change the current position, but it does clear the end-of-file 
     condition on the handle, so that the next "<FILE>" makes Perl 
     try again to read something. We hope. 

Por lo que yo recuerdo, fseek se llama iostream::seekg. Por lo tanto, básicamente debe hacer lo mismo: busque hasta el final del archivo, luego duerma y vuelva a intentar con el indicador ios_base::cur para actualizar el final del archivo y leer algunos datos más.

En lugar de sleep ing, puede utilizar inotify, como se sugiere en the other answer, para dormir (bloquear al leer desde un archivo emulado, en realidad) exactamente hasta que el archivo se actualice/cierre. Pero eso es específico de Linux, y no es C++ estándar.

+0

adoramos el cierre de "esperamos".Se combina bien con "esto es extraño, pero es bueno porque es raro" y las muchas otras realizaciones de autoataque que son tan típicas de perl ... –

+0

@Stefano - bueno, es bueno aquí porque se relaciona con la implementación de Perl en línea lectura de archivo (''), y no se trata de cómo funciona 'fseek'. Espero. –

1

Necesitaba implementar esto también, acabo de escribir un truco rápido en C++ estándar. El truco busca el último 0x0A (carácter de avance de línea) en un archivo y emite todos los datos siguientes a ese salto de línea cuando el último valor de avance de línea se convierte en un valor mayor. El código está aquí:

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

using namespace std; 


int find_last_linefeed(ifstream &infile) { 

    infile.seekg(0,ios::end); 
    int filesize = infile.tellg(); 

    for(int n=1;n<filesize;n++) { 
    infile.seekg(filesize-n-1,ios::beg); 

    char c; 
    infile.get(c); 

    if(c == 0x0A) return infile.tellg(); 
    } 
} 


int main() { 


    int last_position=-1; 
    for(;;) { 

    ifstream infile("testfile"); 
    int position = find_last_linefeed(infile); 

    if(position > last_position) { 
     infile.seekg(position,ios::beg); 
     string in; 
     infile >> in; 
     cout << in << endl; 
    } 
    last_position=position; 

    sleep(1); 
    } 

} 
2

Igual que en https://stackoverflow.com/a/7514051/44729 excepto que el código siguiente se utiliza getline en lugar de getc y no salta nuevas líneas

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

using namespace std; 

static int last_position=0; 
// read file untill new line 
// save position 

int find_new_text(ifstream &infile) { 

    infile.seekg(0,ios::end); 
    int filesize = infile.tellg(); 

    // check if the new file started 
    if(filesize < last_position){ 
     last_position=0; 
    } 
    // read file from last position untill new line is found 

    for(int n=last_position;n<filesize;n++) { 

     infile.seekg(last_position,ios::beg); 
     char test[256]; 
     infile.getline(test, 256); 
     last_position = infile.tellg(); 
     cout << "Char: " << test <<"Last position " << last_position<< endl; 
     // end of file 
     if(filesize == last_position){ 
     return filesize; 
     } 

    } 

    return 0; 
} 


int main() { 

    for(;;) { 
    std::ifstream infile("filename"); 
    int current_position = find_new_text(infile); 
    sleep(1); 
    } 

} 
+0

tamaño de archivo Angela

Cuestiones relacionadas