作者:朱金灿
最近要使用C++程序调用python脚本,调用方法是通过启动python进程来调用,其中遇到的一个问题是在C++程序中需要获取python脚本的控制台输出信息。经过摸索使用_popen函数实现了。下面用python脚本和C++调用示例程序来说明。python示例程序如下:
import os
import sys
if __name__ == "__main__":
print("program start!")
print("program end!")
C++示例程序如下:
#include <iostream>
#include <cstdlib>
#include <stdlib.h>
#include <fstream>
#include <string>
#include <map>
#include <thread>
#include <future>
#include <sstream>
//获取python脚本的控制台输出字符串
std::string GetPythonConsoleOutput()
{
std::stringstream ss;
auto py_prog = std::async(std::launch::async, [&ss]()
{
//python命令行
std::string cmd = "python D:\\MyProject\\PythonCodeLib\\UtilityTest\\ConsoleOutput.py";
#ifdef _WINDOWS
FILE* in = _popen(cmd.c_str(), "r");
char buf[1024];
while (fgets(buf, sizeof(buf), in) != NULL)
{
ss << buf;
}
_pclose(in);
#else
FILE* in = popen(cmd.c_str(), "r");
char buf[1024];
while (fgets(buf, sizeof(buf), in) != NULL)
{
ss << buf;
}
pclose(in);
#endif
});
py_prog.wait();
return ss.str();
}
int main()
{
std::string strRet = GetPythonConsoleOutput();
std::cout << strRet << std::endl;
getchar();
return 0;
}
效果图如下:
需要注意的是C++程序用到了C++11中的std::async组件,同时程序是支持跨平台的,创建管道和启动子进程的函数在windows上是_popen,在linux下是popen。还有在Windows平台上使用_popen启动子进程后,如果无法获取到子进程向控制台的输出字符串,主要有以下几个原因:
1)没有正确设置_popen的读写模式
_popen的第二个参数需要设置为"r"才可以读取子进程的输出。如果设置为"w",则只能向子进程输入。
2)未正确读取输出缓冲区
_popen打开进程后,需要通过fgets/fread等函数读取文件句柄,才能获取输出。否则输出可能被缓冲在管道中。
3)子进程未输出到标准输出
子进程内如果没有用cout/printf向标准输出打印,是无法通过_popen读取的。需要子进程也输出到stdout。
4)读取时机错误
如果在子进程退出前就读取_popen句柄,则可能读取不完整。需要在子进程退出后再读取。
5)未正确关闭句柄
需要调用_pclose来关闭_popen的文件句柄,释放资源。
6)重定向导致无法捕获标准输出
子进程内如果重定向了标准输出到文件等其他地方,也无法通过_popen读取。
综上,使用_popen获取子进程输出需要注意读写模式、缓冲读取、标准输出重定向等问题。需要双方配合才能正确传递输出。