Получение вывода на печать из общей библиотеки, вызываемой из python, с помощью модуля ctypes - PullRequest
7 голосов
/ 28 февраля 2012

Я работаю с разделяемой библиотекой, которая вызывается через модуль ctypes.Я хотел бы перенаправить стандартный вывод, связанный с этим модулем, в переменную или файл, к которому я могу получить доступ в моей программе.Однако ctypes использует отдельный стандартный вывод из sys.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()

Можно ли как-нибудь захватить стандартный вывод, связанный с загруженной общей библиотекой ctypes?

Ответы [ 2 ]

5 голосов
/ 29 февраля 2012

Мы можем использовать os.dup2() и os.pipe(), чтобы заменить весь дескриптор файла стандартного вывода (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()
2 голосов
/ 21 декабря 2016

Самый простой пример, потому что этот вопрос в 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...