【问题标题】:Redirect stdout from python for C calls从 python 重定向标准输出以进行 C 调用
【发布时间】:2012-02-06 23:02:42
【问题描述】:

这是来自here 的后续问题,专门针对其answer


我从一个 python 模块调用一个 Hello World 可执行文件,它只是将Hello World 打印到标准输出。我有兴趣将该输出重定向到 python StringIO 并遇到 this 答案,这几乎让我找到了解决方案。

这个答案的关键部分是这段代码:

1. def redirect_stdout():
2.     print "Redirecting stdout"
3.     sys.stdout.flush() # <--- important when redirecting to files
4.     newstdout = os.dup(1)
5.     devnull = os.open('/dev/null', os.O_WRONLY)
6.     os.dup2(devnull, 1)
7.     os.close(devnull)
8.     sys.stdout = os.fdopen(newstdout, 'w')

我还想恢复重定向之前的标准输出。

问题

  1. 上面的函数到底发生了什么?
    • dupdup2 在做什么?
    • 什么是/dev/null
    • 第 8 行在做什么? (sys.stdout = os.fdopen(newstdout, 'w'))
  2. 如何将标准输出存储在 StringIO 对象中?
  3. 如何在调用我的 Hello World 程序后恢复标准输出?

我很确定,一旦我得到问题 1 的答案,问题 2 和 3 的答案就会很容易。无论如何,我决定发布它们,以便将问题 1 的答案推向我想去的方向。

【问题讨论】:

    标签: python stdout io-redirection dup2 dup


    【解决方案1】:

    有关这些 Python 函数基础的 C 运行时函数,请参阅 manual pages

    基本上,它们将文件描述符复制到一个新的文件描述符(使用dup())或复制到调用中指定的文件描述符中,使用dup2()

    【讨论】:

      【解决方案2】:

      /dev/null 是一个特殊的设备文件(UNIX 中的一切都是文件!),它像黑洞一样吞噬写入它的所有内容。 dup 复制了一个文件描述符。如果您习惯于 Windows,则 UNIX 中的文件描述符是一个特殊的整数,表示打开的文件,就像 Windows 文件句柄一样。

      程序正在打开/dev/null 用于写入(仅),获取它的文件描述符的副本,关闭打开的文件(因为拥有文件描述符足以让 UNIX 写入文件,您不需要保持资源打开),然后将打开的文件分配给sys.stdout

      记住sys 是代表各种系统特定资源的 Python 模块,例如文件系统。因此,在 UNIX 中,sys.stdout 将代表/dev/stdout,即系统STDOUT 流。

      所以,总的来说,这段代码让 Python 认为 /dev/null/STDOUT,所以现在每次你的程序使用 print 语句(Python3 中的函数)写入 STDOUT 时,它就会真的要写信给/dev/null,你永远不会在控制台上看到结果文本。

      【讨论】:

        【解决方案3】:

        我在下面写了一些额外的 cmets,它们应该可以更清楚地说明 redirect_stdout 函数内部发生了什么:

        def redirect_stdout():
            print "Redirecting stdout"
            sys.stdout.flush() # <--- important when redirecting to files
        
            # Duplicate stdout (file descriptor 1)
            # to a different file descriptor number
            newstdout = os.dup(1)
        
            # /dev/null is used just to discard what is being printed
            devnull = os.open('/dev/null', os.O_WRONLY)
        
            # Duplicate the file descriptor for /dev/null
            # and overwrite the value for stdout (file descriptor 1)
            os.dup2(devnull, 1)
        
            # Close devnull after duplication (no longer needed)
            os.close(devnull)
        
            # Use the original stdout to still be able
            # to print to stdout within python
            sys.stdout = os.fdopen(newstdout, 'w')
        

        需要注意的重要一点是,一个进程在启动时会从操作系统获得三个不同的file descriptors

        • 标准输入:0
        • 标准输出:1
        • 标准错误:2

        正如 cmets 中所解释的,上面的代码利用 stdout 的文件描述符和文件描述符复制函数来欺骗 C 代码使用不同的 stdout,同时仍然保持对 python 代码中原始 stdout 的引用能够打印。

        【讨论】:

        • 如果我用redirect_stdout 重定向了标准输出。我将如何再次恢复标准输出,以便外部程序可以打印到标准输出? os.dup2(1, devnull) 似乎不起作用?!
        • 应该是os.dup2(newstdout, 1)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-06
        • 2013-05-03
        • 1970-01-01
        相关资源
        最近更新 更多