【问题标题】:Repeated redirection of low-level stdin in PythonPython中低级标准输入的重复重定向
【发布时间】:2013-11-15 11:43:06
【问题描述】:

这是我的情况:有一些旧的 C++ 代码,我正在尝试为其创建一个简单的 Python 包装器。此代码最初设计为从命令行驱动,并期望将输入文件通过管道传输到其中。为了尽量减少对这段代码的干扰,我将 main 函数转换为 vanilla extern "C" 函数并将其编译成一个共享库,我在 Python 中加载并通过 ctypes 驱动。请注意,我不想通过系统调用来驱动这段代码,因为它最终会在集群上运行并执行无数次。

从这里开始,我需要控制较低级别的标准输入以设置输入文件,以便可以通过 C++ 代码中的各种“cin”语句读取它。

从我目前所学的来看,理论上我可以通过使用 os 库覆盖标准输入文件描述符来做到这一点。我编写了以下示例,它似乎在 Python 中运行良好(基于此线程中的各种信息:Python version of 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']

(以及两个文件“hello”和“hello2”)对我来说。很好!不幸的是,当我的 C++ 库函数正在读取标准输入流时,它似乎不起作用。奇怪的是,它第一次工作得很好,但第二次却失败了;没有发生错误,看起来更像是 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' 处理标准输入似乎与这种标准输入重定向方法完全兼容。唔。当然,通过此方法创建一个新的“cat”进程,并且每次都会连接新的标准输入,所以它与调用我的库函数并不完全相同。我将尝试创建一个重现问题的最小库函数...

【问题讨论】:

  • 当您说它“第一次”有效时,您的确切意思是什么?只有第一行,第一次重启Python前,还是……?
  • 啊抱歉。我的意思是我第一次执行重定向+运行库函数。整个库函数按预期执行。但是,如果稍后我重复该过程,将 stdin 重定向到一个新文件,如我的示例所示,则如果几行 python 行之后,库函数似乎没有从其 cin 调用中接收到任何输入并且失败。
  • 基本上用调用库函数替换我的python示例中的“print sys.stdin.readlines()”来得到我的意思。

标签: c++ python io-redirection


【解决方案1】:

啊哈!事实证明,这个问题很有帮助:cin.ignore() and cin.clear() in C++

因此,至少在 C++ 中,当流到达 eof 时,它会将各种错误标志设置为 true (http://www.cplusplus.com/reference/ios/ios/good/)。这可以防止对流执行进一步的操作。当我的库代码是一个独立的可执行文件时,这种行为很好,因为程序只会尝试从 cin 读取文件一次。但是,将代码转换为库后,当我的循环再次返回调用库函数时,库函数仍在处理相同的标准输入流。流仍然设置了错误标志,因此第二次传递时 cin 读取失败。

为了解决问题,我添加了

std::cin.clear();

到库代码,在尝试 cin 读取之前。这会重置流的错误标志,然后可以正常读取。

我不确定是否可以在 Python 端处理流标志的重置;很高兴知道这一点。

【讨论】:

    猜你喜欢
    • 2012-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    相关资源
    最近更新 更多