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:).
As discovered in the comments, you are not reading a "real" file on disk, but rather /proc/PID/io which is a virtual file whose contents may only be determined when it is opened, thanks to VFS. Your statement that it can "change arbitrarily by some other process" is misleading, the file never changes, it simply has different content each time it is opened.
So now we know that no amount of seeking will help. We simply need to open the file afresh each time we want to read it. That can be done fairly simply:
char content[1000]; // choose a suitable value
const char key[] = "read_bytes:";
while (true)
{
std::ifstream io(io_filename);
if (!io.read(content, sizeof(content)))
break;
auto it = std::search(content, std::end(content), key, key + strlen(key));
std::cout << atoi(it + strlen(key)) << std::endl;
}
You should do something more careful than atoi() which won't stop at the end of the array, but I assume your real application will do something else there so I elided handling that.
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++
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With