В настоящее время я пытаюсь запустить файл, написанный на python, из моей программы на C ++ с помощью библиотеки pstream (http://pstreams.sourceforge.net/). Мой код выглядит так:
QStringList res;
QStringList resErrors;
// run a process and create a streambuf that reads its stdout and stderr
redi::pstream proc(cmd, redi::pstreams::pstdout | redi::pstreams::pstderr);
std::string line;
// read child's stdout
while (std::getline(proc.out(), line))
res.append(QString::fromStdString(line));
// read child's stderr
while (std::getline(proc.err(), line))
resErrors.append(QString::fromStdString(line));
Обычно я правильно получаю сообщение об ошибке и ошибку от любой команды, введенной в конструкторе pstream. Но если я попытаюсь выполнить файл Python, который вызывает трассировку, у меня не будет никакого вывода (в stdout или в stderr).
Например, этот файл Python:
#!/usr/bin/env python
test = 5 / 0
print "test"
не будет печатать «тест» в stdout и ничего в stderr. Но если я выполню это в терминале, я правильно получу:
Traceback (most recent call last):
File "test.py", line 3, in <module>
test = 5 / 0
ZeroDivisionError: integer division or modulo by zero
В обоих случаях я использовал одну и ту же команду: «python test.py»
Я думаю, мне нужно сказать Python, чтобы напечатать его трассировку в stderr? Но почему это не делается в подпроцессе? Или это может быть ошибка в библиотеке?
Еще одна возможность, которую я имею в виду, заключается в том, что я читаю stdout и stderr слишком рано, и у python не было времени писать в нем. Но я пытался добавить функцию сна, прежде чем читать ее, без какого-либо эффекта.
Хорошо, проблема эффективно решена с помощью части ответа от @ Jean-François Fabre.
Я заметил, что pstream предоставляет способ чтения по каналу без блокировки, поэтому я повторно использую этот код (находится в документе библиотеки):
const redi::pstreams::pmode mode = redi::pstreams::pstdout|redi::pstreams::pstderr;
redi::ipstream child(cmd, mode);
char buf[1024];
std::streamsize n;
bool finished[2] = { false, false };
while (!finished[0] || !finished[1])
{
if (!finished[0])
{
while ((n = child.err().readsome(buf, sizeof(buf))) > 0) {
std::string ret(buf, n);
resErrors.append(QString::fromStdString(ret));
}
if (child.eof())
{
finished[0] = true;
if (!finished[1])
child.clear();
}
}
if (!finished[1])
{
while ((n = child.out().readsome(buf, sizeof(buf))) > 0) {
std::string out(buf, n);
res.append(QString::fromStdString(out));
}
if (child.eof())
{
finished[1] = true;
if (!finished[0])
child.clear();
}
}
}
res = res.join("").split("\n");
resErrors = resErrors.join("").split("\n");
res.removeLast();
resErrors.removeLast();
Благодаря этому у меня есть все выходные данные в моих списках QStringLists!
Других решений пока нет …