Вот моя ситуация: есть некоторый старый код C ++, для которого я пытаюсь создать простую оболочку Python. Этот код изначально был разработан для запуска из командной строки и ожидает, что в него будет передан входной файл. В целях минимального вмешательства в этот код я преобразовал основную функцию в ванильную внешнюю функцию «C» и скомпилировал ее в общую библиотеку, которую я загружаю в Python и запускаю через ctypes. Обратите внимание, что я не хочу управлять этим кодом через системные вызовы, так как он будет работать в кластере и выполняться миллионы раз.
Отсюда мне нужно взять под контроль stdin нижнего уровня, чтобы настроить входной файл так, чтобы он мог быть прочитан с помощью различных операторов «cin» в коде C ++.
Из того, что я узнал до сих пор, кажется, что теоретически я могу сделать это, переписав дескрипторы файлов stdin с помощью библиотеки os. Я подготовил следующий пример, который, кажется, прекрасно работает в Python (на основе различной информации в этой теме: Python-версия freopen ()):
import os
import sys
def freopen(f,option,stream):
oldf = open(f,option)
oldfd = oldf.fileno()
newfd = stream.fileno()
os.close(newfd)
os.dup2(oldfd, newfd)
# Original stdout file descriptor:
fd = sys.stdout.fileno()
orig_stream = os.fdopen(os.dup(fd), 'w')
# Test writing to file:
freopen("hello","w",sys.stdout)
print "world"sys.stdout.flush()
freopen("hello2","w",sys.stdout)
print "world2"sys.stdout.flush()
# Restore stdout to normal
os.dup2(orig_stream.fileno(),sys.stdout.fileno())
print "back to normal!"
# Test reading:
freopen("hello","r",sys.stdin)
print sys.stdin.readlines()
freopen("hello2","r",sys.stdin)
print sys.stdin.readlines()
Это производит вывод
back to normal!
['world\n']
['world2\n']
(а также два файла «привет» и «привет2») для меня. Так здорово! К сожалению, это не работает, когда поток stdin читается моей библиотечной функцией C ++. Странно, но в первый раз он работает просто отлично, но во второй раз не получается; ошибки не возникает, похоже, поток stdin просто пуст для второго перенаправления. Когда я перенаправляю стандартный вывод вместо стандартного, он работает нормально.
Что-то особенное, что мне нужно сделать, чтобы сбросить поток stdin нижнего уровня для второго прохода?
Дополнительная информация: на стороне c ++ stdin читается так:
while (getline(cin,line)) {
// do stuff with line...
Также я не слишком обеспокоен, если решение «только для Linux».
Изменить: я использую Python 2.7.1
Обновление: Хм, может быть, библиотечный код делает что-то странное, потому что если я изменю часть «теста чтения» моего тестового кода на это:
# Test reading:
freopen("hello","r",sys.stdin)
os.system("cat")
freopen("hello2","r",sys.stdin)
os.system("cat")
Тогда ожидаемый выход
back to normal!
world
world2
все еще производится. Таким образом, как бы «кошка» ни относилась к стандартному вводу данных, кажется, что он полностью совместим с этим методом перенаправления стандартного ввода. Хм. Конечно, с помощью этого метода создается новый процесс «cat», и каждый раз к нему подключается новый stdin, так что на самом деле это не то же самое, что вызов функции моей библиотеки. Я постараюсь создать минимальную библиотечную функцию, которая воспроизводит проблему …
Ага! Так что, как оказалось, этот вопрос очень помог: cin.ignore () и cin.clear () в C ++
Похоже, что, по крайней мере, в C ++, когда поток достигает eof, он устанавливает для различных флагов ошибки значение true (http://www.cplusplus.com/reference/ios/ios/good/). Это предотвращает выполнение дальнейших операций в потоке. Когда мой библиотечный код был автономным исполняемым файлом, это было нормально, потому что программа пыталась прочитать файл из cin только один раз. Однако с кодом, преобразованным в библиотеку, когда мой цикл вернулся к вызову библиотечной функции во второй раз, библиотечная функция все еще работала с тем же потоком stdin. В потоке все еще были установлены флаги ошибок, поэтому чтение cin завершилось неудачно на этом втором проходе.
Чтобы решить проблему, я добавил
std::cin.clear();
к коду библиотеки, до того, как были сделаны попытки чтения cin. Это сбрасывает флаги ошибок для потока, которые затем могут быть прочитаны очень хорошо.
Я не уверен, может ли эта переустановка потоковых флагов иметь дело со стороной Python или нет; это было бы полезно знать.
Других решений пока нет …