如何读取C ++中的system()调用的结果?

我正在使用下面的代码尝试在Linux中使用popen读取df命令的结果。

 #include <iostream> // file and std I/O functions int main(int argc, char** argv) { FILE* fp; char * buffer; long bufSize; size_t ret_code; fp = popen("df", "r"); if(fp == NULL) { // head off errors reading the results std::cerr << "Could not execute command: df" << std::endl; exit(1); } // get the size of the results fseek(fp, 0, SEEK_END); bufSize = ftell(fp); rewind(fp); // allocate the memory to contain the results buffer = (char*)malloc( sizeof(char) * bufSize ); if(buffer == NULL) { std::cerr << "Memory error." << std::endl; exit(2); } // read the results into the buffer ret_code = fread(buffer, 1, sizeof(buffer), fp); if(ret_code != bufSize) { std::cerr << "Error reading output." << std::endl; exit(3); } // print the results std::cout << buffer << std::endl; // clean up pclose(fp); free(buffer); return (EXIT_SUCCESS); } 

这个代码给了我一个“内存错误”,退出状态为“2”,所以我可以看到它的失败,我只是不明白为什么

我从Ubuntu论坛和C ++ Reference中find的示例代码组合在一起,所以我没有结婚。 如果任何人都可以提出一个更好的方法来读取system()调用的结果,我可以接受新的想法。

编辑原文:好吧, bufSize是负面的,现在我明白了为什么。 你不能随意访问一个pipe道,因为我天真地试图做。

我不能成为第一个尝试这样做的人。 有人可以给(或指向我)一个如何读取一个system()调用的结果在C ++中的variables的例子?

Solutions Collecting From Web of "如何读取C ++中的system()调用的结果?"

为什么会std::malloc()失败?

显而易见的原因是“因为std::ftell()返回了一个负数的有符号数,然后被视为一个巨大的无符号数”。

根据文档 , std::ftell()在失败时返回-1。 一个明显的失败原因是你不能在管道或FIFO中寻找

跑不了的; 如果不读取命令输出,则无法知道命令输出的长度,只能读取一次。 你必须分块阅读,或者根据需要增加缓冲区,或者动态分析。

但是,当然,你可以通过直接使用系统调用来避免整个问题, df可能用来获取它的信息: statvfs()

你让这个太难了 popen(3)为一个标准管道文件返回一个普通的旧FILE * ,也就是说,换行符终止的记录。 你可以通过使用fgets(3)来以非常高的效率读取它,就像C:

 #include <stdio.h> char bfr[BUFSIZ] ; FILE * fp; // ... if((fp=popen("/bin/df", "r")) ==NULL) { // error processing and return } // ... while(fgets(bfr,BUFSIZ,fp) != NULL){ // process a line } 

在C ++中更容易 –

 #include <cstdio> #include <iostream> #include <string> FILE * fp ; if((fp= popen("/bin/df","r")) == NULL) { // error processing and exit } ifstream ins(fileno(fp)); // ifstream ctor using a file descriptor string s; while (! ins.eof()){ getline(ins,s); // do something } 

这里有更多的错误处理,但这是主意。 重点是你像从任何 FILE *一样对待FILE * ,并逐行阅读。

我不确定你可以这样做。

你检查了bufSize的值吗? malloc失败的一个原因是疯狂大小的缓冲区。

(关于术语的说明:Unix和Linux中的“系统调用”通常是指从用户空间代码调用内核函数,称之为“ system()调用的结果”或“ system(3)结果” system(3)调用“会更清晰,但只是说”捕获进程的输出“可能会更好。)

无论如何,您可以像读取其他文件一样读取进程的输出。 特别:

  • 您可以使用pipe()fork()exec()来启动进程。 这给你一个文件描述符,然后你可以使用一个循环来从文件描述符中read()到缓冲区中,并在完成之后close()文件描述符。 这是最低级别的选项,并给你最大的控制。
  • 你可以像使用popen()一样开始这个过程。 这给你一个文件流。 在一个循环中,您可以使用fread()fgets()fgetc()从流中读取到临时变量或缓冲区,如Zarawesome的答案所示,然后处理该缓冲区或将其附加到C ++字符串。
  • 你可以使用popen()来启动进程,然后使用非标准的__gnu_cxx :: stdio_filebuf将其包装起来,然后从stdio_filebuf创建一个std::istream ,并像对待任何其他C ++流一样处理它。 这是最类似于C ++的方法。 这是第一部分和第二部分的一个例子。

感谢大家花时间回答。 一位同事指着我ostringstream类。 以下是一些示例代码,它基本上是我在原始问题中尝试做的事情。

 #include <iostream> // cout #include <sstream> // ostringstream int main(int argc, char** argv) { FILE* stream = popen( "df", "r" ); std::ostringstream output; while( !feof( stream ) && !ferror( stream )) { char buf[128]; int bytesRead = fread( buf, 1, 128, stream ); output.write( buf, bytesRead ); } std::string result = output.str(); std::cout << "<RESULT>" << std::endl << result << "</RESULT>" << std::endl; return (0); } 

要回答更新中的问题:

 char buffer[1024]; char * line = NULL; while ((line = fgets(buffer, sizeof buffer, fp)) != NULL) { // parse one line of df's output here. } 

这足够吗?

首先要检查的是bufSize的值 – 如果碰巧<= 0,那么malloc会返回一个NULL,因为您正试图在该点分配一个大小为0的缓冲区。

另一个解决方法是让malloc为你提供一个大小为(bufSize + n)的缓冲区,其中n> = 1,这应该解决这个问题。

除此之外,你发布的代码是纯粹的C,而不是C ++,因此包括一点点的过度。

检查你的bufSize。 ftell在错误时可以返回-1,这可能导致malloc与具有NULL值的缓冲区非分配。

失败的原因是,因为popen。 你不能搜索管道。

管道不是随机访问。 它们是连续的,这意味着一旦你读了一个字节,管道就不会再发送给你了。 这显然意味着你不能倒带。

如果您只想将数据输出回用户,则可以执行如下操作:

 // your file opening code while (!feof(fp)) { char c = getc(fp); std::cout << c; } 

这会将字节逐个从df管道中拉出,然后将它们直接泵入输出。

现在,如果要整体访问df输出,可以将其输入到文件中并读取该文件,也可以将输出连接到C ++字符串等构造中。