0

I've been trying to call another program from c++, and save the stout of that program to a text file. popen() seems to be the appropriate function, but saving it to a text file isn't working.

      ofstream delaunayfile;
    delaunayfile.open ("triangulation/delaunayedpoints.txt");
      FILE *fp;
      fp = popen("qdelaunay < triangulation/rawpoints.txt", "r");
    delaunayfile << fp;
    delaunayfile.close();

Any help? Thanks in advance!

James
  • 13
  • 1
  • 4

3 Answers3

2

You cannot write a FILE* directly into a stream. It will write a memory address instead of the actual file contents, therefore it will not give you the desired result.

The ideal solution would be to read from an ifstream and write to your ofstream, but there's no way to construct an ifstream from a FILE*.

However, we can extend the streambuf class, make it work over a FILE*, and then pass it to an istream instead. A quick search revealed someone already implemented that, and properly named popen_streambuf. See this specific answer.

Your code then would look like this:

std::ofstream output("triangulation/delaunayedpoints.txt");
popen_streambuf popen_buf;
if (popen_buf.open("qdelaunay < triangulation/rawpoints.txt", "r") == NULL) {
    std::cerr << "Failed to popen." << std::endl;
    return;
}
char buffer[256];
std::istream input(&popen_buf);
while (input.read(buffer, 256)) {
    output << buffer;
}
output.close();

As pointed by Simon Richter in comments, there's an operator<< that accepts streambuf and writes data to ostream until EOF is reached. This way, the code would be simplified to:

std::ofstream output("triangulation/delaunayedpoints.txt");
popen_streambuf popen_buf;
if (popen_buf.open("qdelaunay < triangulation/rawpoints.txt", "r") == NULL) {
    std::cerr << "Failed to popen." << std::endl;
    return;
}
output << &popen_buf;
output.close();
Community
  • 1
  • 1
jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • 1
    note that in your example, you could also use `output << &popen_buf;` to copy the data, as there is an `operator<<(std::ostream &, std::streambuf *);`. – Simon Richter Jan 20 '11 at 11:36
  • @Simon Richter: oh, I completely missed that! Updated to mention your suggestion. Thank you! – jweyrich Jan 20 '11 at 11:52
0

There are two ways to do this: The simple way

int rc = system("qdelaunay < triangulation/rawpoints.txt >triangulation/delaunayedpoints.txt");

and the slightly more elaborate way, using fork(), dup2() and execve(), the latter working without a shell interpreter installed on the system. Given that this looks like you are doing computation work, I suspect this is not an embedded system, so you can assume a working shell.

Simon Richter
  • 28,572
  • 1
  • 42
  • 64
0

popen opens a pipe but I am not aware you can just stream it into delaunayfile that way.

Of course it would be very nice if you could just do that and it would read from the pipe until it was complete.

The normal way to check for data on the pipe is to use select(). I found a useful link http://codenewbie.com/forums/threads/2908-Using-std-fstream-in-a-pipe that integrates pipes with fstream though and it may help you achieve what you want.

In this instance though as all you want to do is write the output to a file, why not redirect the output of the process to it rather than to a pipe? The purpose of a pipe is Inter-Process communication but your process does not appear to be using the data it receives from the other process for any practical purpose.

CashCow
  • 30,981
  • 5
  • 61
  • 92