tags:

views:

300

answers:

3

Hi! I want to create a small code in C++ with the same functionality as "tail-f": watch for new lines in a text file and show them in the standard output.

The idea is to have a thread that monitors the file

Is there an easy way to do it without opening and closing the file each time?

+5  A: 

Just keep reading the file. If the read fails, do nothing. There's no need to repeatedly open and close it. However, you will find it much more efficient to use operating system specific features to monitor the file, should your OS provide them.

anon
+1: Trying to read to the end of the file from where you've got to so far (for a reasonable length file) once a second is pretty cheap in practice. You just read until you've got to the end, then sleep for a second and try the read again. (If you're on Windows, take care to open with the right sharing flags so that you don't lock out other writers. That probably means using the native IO calls rather than the C++ standard ones...)
Donal Fellows
+1  A: 

Have a look at inotify on Linux or kqueue on Mac OS.

Inotify is Linux kernel subsystem that allows you to subscribe for events on files and it will report to your application when the even happened on your file.

stefanB
Windows has an equivalent API for sending notifications when a file changes.
Thomas Matthews
+1  A: 

I read this in one of Perl manuals, but it is easily translated into standard C, which, in turn, can be translated to istreams.

   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.

As far as I remember, fseek is called iostream::seekg. So you should basically do the same: seek to the end of the file, then sleep and seek again with ios_base::cur flag to update end-of-file and read some more data.

Instead of sleeping, you may use inotify, as suggested in the other answer, to sleep (block while reading from an emulated file, actually) exactly until the file is updated/closed. But that's Linux-specific, and is not standard C++.

Pavel Shved
love the "we hope" closing. Sticks well together with "this is weird, but it's good because it's weird" and the many other self-bashing realizations that are so typical of perl...
Stefano Borini
@Stefano - well, it's good here because it relates to Perl's implementation of linewise file reading (`<FILE>`), and is not about how `fseek` works. I hope.
Pavel Shved