我正在使用通过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加载的共享库相关联的标准输出?
我们可以使用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)