Skip to content
Advertisement

Read a file that’s constantly updated (C++)

Let me start with saying that I’m around 3 days old in C++.

Ok to the main question, I have a file that spans multiple lines, and I’m trying to print one specific line repeatedly, which is subject to change arbitrarily by some other process.

Example file :

line0
line1
somevar: someval
line3
line4

I’m trying to print the middle line (one that starts with somevar). My first naive attempt was the following where I open the file, loop through the contents and print the exact line, then move to the beginning of the file.

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

int main (int argc, char *argv[])
{
    std::string file = "input.txt";
    std::ifstream io {file};

    if (!io){
        std::cerr << "Error opening file" <<std::endl;
        return EXIT_FAILURE;
    }

    std::string line;
    std::size_t pos;
    
    while (getline (io, line))
    {
        pos = line.find_first_of(' ');
        if (line.substr (0, pos) == "somevar:")
        {
            // someval is expected to be an integer
            std::cout << std::stoi( line.substr (pos) ) ) << std::endl;
            io.seekg (0, std::ios::beg);
        }
    }

    io.close();

    return EXIT_SUCCESS;
}

Result : Whenever the file’s updated, the program exits.

I came to think the fact that the IO I’m performing is actually buffered, therefore updating the file shouldn’t reflect in our existing buffer just like that (this isn’t shell scripting). So now I thought let’s open and close the file on each iteration, which should effectively refresh the buffer every time, I know not the best solution, but I wanted to test the theory. Here’s the new source :

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

int main (int argc, char *argv[])
{
    std::string proc_file = "input.txt";
    std::ifstream io;

    if (!io){
        std::cerr << "Error opening file" <<std::endl;
        return EXIT_FAILURE;
    }
    std::string line;
    std::size_t pos;
    
    while (io.open(proc_file, std::ios::in), io)
    {
        io.sync();
        getline (io, line); 
        pos = line.find_first_of(' ');
        // The line starting with "somevar:" is always going to be there.
        if (line.substr (0, pos) == "somevar:")
        {
            std::cout << std::stoi( line.substr (pos) ) ) << std::endl;
            io.close();
        }
    }

    io.close();

    return EXIT_SUCCESS;
}

Result : Same as before.

What would be the ideal way of achieving what I’m trying to? Also, why’s the program exiting whenever the file in question is being updated? Thanks (:

EDIT: The file I’m trying to read is "/proc/" + std::to_string( getpid() ) + "/io", and the line is the bytes read one (starts with read_bytes:).

Advertisement

Answer

The file I’m trying to read is some /proc/1234/io

That is the most important information.

Files in proc(5) are small pseudo-files (a bit like pipe(7)-s) which can only be read in sequence.

That pseudo file is not updated, but entirely regenerated (by the Linux kernel whose source code you can study) at every open(2)

So you just read all the file quickly in memory, and process that content in memory once you have read it.

See this answer to a very related question…. Adapt it to C++

Advertisement