2012-02-28 85 views
5

我正在通過ctypes模塊調用共享庫。我想將與此模塊關聯的stdout重定向到一個變量或一個我可以在我的程序中訪問的文件。但是ctypes使用sys.stdout中的一個單獨的stdout。從ctypes模塊中從python調用共享庫捕獲打印輸出

我將用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() 

的文件名有什麼辦法,我可以捕獲與ctypes的相關加載的共享庫中的標準輸出?

回答

5

我們可以使用os.dup2()os.pipe()來用我們自己讀取的管道替換整個stdout文件描述符(fd 1)。你可以用stderr(fd 2)做同樣的事情。

本示例使用select.select()來查看pipe(我們的僞標準輸出)是否有數據等待寫入,因此我們可以安全地進行打印而不會阻止腳本的執行。

由於我們完全替代了此進程和任何子進程的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() 
0

最簡單的例子,因爲這個問題在谷歌頂部。

import os 
from ctypes import CDLL 

libc = CDLL(None) 
stdout = os.dup(1) 
silent = os.open(os.devnull, os.O_WRONLY) 
os.dup2(silent, 1) 
libc.printf(b"Hate this text") 
os.dup2(stdout, 1)