2012-02-28 14 views
5

Sto lavorando con una libreria condivisa che viene chiamata attraverso il modulo ctypes. Vorrei reindirizzare lo stdout associato a questo modulo a una variabile oa un file a cui posso accedere nel mio programma. Tuttavia, i ctype utilizzano uno stdout separato da sys.stdout.Cattura output di stampa dalla libreria condivisa chiamata da python con modulo ctypes

Mostrerò il problema che sto avendo con libc. Se qualcuno sta copiando e incollando il codice che potrebbe essere necessario modificare il nome del file on line 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() 

C'è un modo per catturare l'stdout che è associato con i ctypes caricato libreria condivisa?

risposta

5

Possiamo usare os.dup2() e os.pipe() per sostituire l'intero descrittore di file stdout (fd 1) con una pipe che possiamo leggere da noi stessi. Puoi fare la stessa cosa con stderr (fd 2).

Questo esempio utilizza select.select() per verificare se la pipe (il nostro falso stdout) contiene dati in attesa di essere scritti, in modo che possiamo stampare in modo sicuro senza bloccare l'esecuzione del nostro script.

Dato che stiamo sostituendo completamente il descrittore di file stdout per questo processo e qualsiasi sottoprocesso, questo esempio può anche acquisire l'output dai processi figli.

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

Esempio più semplice, perché questa domanda in Google Top.

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) 
Problemi correlati