使用ctypes模块捕获从python调用的共享库的打印输出

ncR*_*ert 7 python

我正在使用通过ctypes模块调用的共享库.我想将与此模块关联的stdout重定向到我可以在程序中访问的变量或文件.但是,ctypes使用sys.stdout中的单独stdout.

我将用libc演示我遇到的问题.如果有人复制并粘贴代码,他们可能需要更改第2行的文件名.

import ctypes
libc = ctypes.CDLL('libc.so.6')

from cStringIO import StringIO
import sys
oldStdOut = sys.stdout
sys.stdout = myStdOut = StringIO()

print 'This text gets captured by myStdOut'
libc.printf('This text fails to be captured by myStdOut\n')

sys.stdout = oldStdOut
myStdOut.getvalue()
Run Code Online (Sandbox Code Playgroud)

有没有什么办法可以捕获与ctypes加载的共享库相关联的标准输出?

lun*_*chs 5

我们可以使用os.dup2()os.pipe()替换整个stdout文件描述符(fd 1),我们可以从自己读取管道.你可以用stderr(fd 2)做同样的事情.

此示例用于select.select()查看管道(我们的假stdout)是否有等待写入的数据,因此我们可以安全地打印它而不会阻止执行我们的脚本.

由于我们正在完全替换此进程和任何子进程的stdout文件描述符,因此该示例甚至可以捕获子进程的输出.

import os, sys, select

# the pipe would fail for some reason if I didn't write to stdout at some point
# so I write a space, then backspace (will show as empty in a normal terminal)
sys.stdout.write(' \b')
pipe_out, pipe_in = os.pipe()
# save a copy of stdout
stdout = os.dup(1)
# replace stdout with our write pipe
os.dup2(pipe_in, 1)

# check if we have more to read from the pipe
def more_data():
        r, _, _ = select.select([pipe_out], [], [], 0)
        return bool(r)

# read the whole pipe
def read_pipe():
        out = ''
        while more_data():
                out += os.read(pipe_out, 1024)

        return out

# testing print methods
import ctypes
libc = ctypes.CDLL('libc.so.6')

print 'This text gets captured by myStdOut'
libc.printf('This text fails to be captured by myStdOut\n')

# put stdout back in place 
os.dup2(stdout, 1)
print 'Contents of our stdout pipe:'
print read_pipe()
Run Code Online (Sandbox Code Playgroud)