1

I am looking to write some code to monitor a file. When it gets written to I would like to read the new lines and act upon them.

So I found this thread: how-to-read-a-growing-text-file-in-c and it shows me how to do this.

However, its a bit of a "polling" approach. Here is the code snippet for convenience. Note: this is not my work (its the answer from the link):

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

You can see there is the comment: You may want a sleep in here to avoid being a CPU hog.

Is there a way (and there might not be) to wait for the file to be written to, such that some event/condition triggers our thread to wake up? I am thinking along the lines of select() like function... But I would really like it to be pure c++.

Failing that - is there a non-pure c++ way (for me I require it to work for Linux OS and possibly windows as well)?

I have not written any code yet because I am not even sure where the best place to start is.

code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • @Marcel, not "written" but "written to": so whenever someone/thing externally writes to it. If start my wait, I would want to wake up whenever that file has been modified. Also - this is a local file on the same file system (no network). – code_fodder Aug 15 '18 at 06:27
  • 2
    Untested, but I think you don't need to sleep at all, just ignore `eof()` and `getline()` will block until new data shows up. By default it throws but apparently you can configure the stream to not do that with `ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit)`, anyway I would start by experimenting with that. – Havenard Aug 15 '18 at 06:28
  • @Havenard ah... that sounds quite promising, I will start to experiment : ) – code_fodder Aug 15 '18 at 06:29
  • 1
    Maybe you can use `inotify` to know when there is a change.... https://www.thegeekstuff.com/2010/04/inotify-c-program-example – PhoenixBlue Aug 15 '18 at 06:40
  • @PhoenixBlue thanks for that, I will keep that in mind if I can't get the pure c++ way to work :p – code_fodder Aug 15 '18 at 06:51
  • @havenard: that would work on a pipe, or a console, or a socket, etc. But not on a file. When you read at the end of a file, the OS just signals end of file. – rici Aug 15 '18 at 07:26
  • @merlin2011 whereas I don't think this is an exact duplicate, because I am specifically looking for pure c++ methods. It does have very useful answers in it, but does not contain a platform independent way of waiting for a file to be modified. I am still (slowly) tinkering with Havenard's idea. Great link though, if Hav's idea does not work then I think this could probably be considered a dup (i.e. if its just not possible in pure c++). – code_fodder Aug 15 '18 at 07:34
  • @code_fodder, Filesystems are usually owned by the OS kernel, so it's hard for me to imagine a pure C++ solution that doesn't use some library to wrap the syscalls into different OSes. – merlin2011 Aug 15 '18 at 07:38
  • 1
    There is no way to do this with the standard C++ library. The dupe does provide a good list of platform specific solutions. On Linux , use [inotify](http://man7.org/linux/man-pages/man7/inotify.7.html). – rici Aug 15 '18 at 07:38
  • 1
    No pure c++ or c way. You need to use an OS API, such as Posix for Linux and Windows API for Windows. POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/ WINDOWS: https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletime – SeanRamey Aug 15 '18 at 07:48
  • @rici and Sean ok, I agree with this - I have tried Hav's solution, but I can't get that idea to work. – code_fodder Aug 15 '18 at 07:56
  • @sean: i don't believe Posix offersthis feature either. Linux, FreeBSD and Solaris have completely different approaches. – rici Aug 15 '18 at 08:06
  • Ok, so the POSIX link is to the home page, and the homepage dynamically generates the content without changing the URL.... so, go to that link, go to "headers" on the left, then to "sys/stat.h", and you should find what I wanted you to see. – SeanRamey Aug 19 '18 at 21:43

1 Answers1

2

you just need to add sleep function that works on both Win and Linux, thus you can use it std::this_thread::sleep_for(std::chrono::milliseconds(500)); in your code. it's from std library so you can use it on Linux or Windows.

#include <chrono>
#include <thread>
#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.
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    return 0;
}
Hamidreza
  • 81
  • 1
  • 6
  • 2
    I think you mis-read my question... or I was not clear... But I am not asking how to use sleep. I want to know how I can wait for a file to be written to. sleeping for 10ms is a very different thing :p – code_fodder Aug 15 '18 at 07:15
  • Got it, for this purpose you can use QFileSystemWatcher, it has function that notify you when a file or folder has been modified. Since Qt is a cross platform framework, your code will be able to compile and run on Varied range of OS . – Hamidreza Aug 18 '18 at 12:23
  • It's a valid point. I've used Qt quite a lot but I don't really want to include the Qt frame work just for this :p – code_fodder Aug 18 '18 at 13:46
  • another way is using OS API. you can use it for Win and Linux, at compiling time you can specify which one will compiled with preprocessors. Also you'll need to implement wrapper for them. – Hamidreza Aug 19 '18 at 05:24