2012-02-28 16 views
5

Estoy trabajando con una biblioteca compartida a la que se llama a través del módulo ctypes. Me gustaría redireccionar el stdout asociado con este módulo a una variable o un archivo al que pueda acceder en mi programa. Sin embargo, ctypes usa una salida estándar separada de sys.stdout.Captura de salida de impresión desde la biblioteca compartida llamada desde python con el módulo ctypes

Voy a demostrar el problema que estoy teniendo con libc. Si alguien está copiando y pegando el código que podría tener que cambiar el nombre del archivo en la línea 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() 

¿Hay alguna manera de que pueda capturar la salida estándar que se asocia con los ctypes cargado biblioteca compartida?

Respuesta

5

Podemos usar os.dup2() y os.pipe() para reemplazar todo el descriptor de archivo stdout (fd 1) con un tubo que podamos leer nosotros mismos. Puedes hacer lo mismo con stderr (fd 2).

Este ejemplo utiliza select.select() para ver si la tubería (nuestra falsa extensión estándar) tiene datos en espera de ser escritos, por lo que podemos imprimir de forma segura sin bloquear la ejecución de nuestra secuencia de comandos.

Como estamos reemplazando completamente el descriptor de archivo stdout para este proceso y cualquier subproceso, este ejemplo puede incluso capturar resultados de procesos secundarios.

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

Simplest ejemplo, porque esta pregunta en google superior.

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) 
Cuestiones relacionadas