Совместное использование выходных потоков через интерфейс JNI

Я пишу приложение Java, которое использует библиотеку C++ через интерфейс JNI. Библиотека C++ создает объекты типа Foo, которые должным образом передаются через JNI в Java.

Предположим, что в библиотеке есть функция вывода

void Foo::print(std::ostream &os)

и у меня есть Java OutputStream out. Как я могу вызвать Foo::print из Java, чтобы вывод отображался на out? Есть ли способ принудить OutputStream к std::ostream на уровне JNI? Могу ли я захватить вывод в буфер слоя JNI, а затем скопировать его в out?


person Chris Conway    schedule 16.09.2009    source источник


Ответы (3)


Я бы реализовал ostream C++, который буферизует записи (до некоторого заданного размера), прежде чем сбрасывать эти записи в java OutputStream через JNI.

На стороне java вы можете либо использовать обычный экземпляр OutputStream, либо реализовать организацию очереди буферных блоков (по сути, byte[]), чтобы избежать любых возможных конфликтов блокировки между потоками. Реальный выходной поток используется только задачей в другом потоке, которая извлекает блоки из очереди и записывает их в OutpuStream. Я не могу сказать, необходимо это или нет на этом уровне детализации - вы вполне можете обнаружить, что запись напрямую в выходной поток из JNI работает.

Я не разделяю опасений других плакатов с JNI и не вижу никаких проблем с использованием JNI для этого. Конечно, ваши сопровождающие должны будут знать свое дело, но это все, а сложность слоя Java/C++ можно решить с помощью документации, примеров и тестовых случаев. В прошлом я реализовал мост Java‹>COM с довольно болтливым интерфейсом — никаких проблем с производительностью, многопоточностью или обслуживанием.

При наличии абсолютно свободного выбора не было бы JNI, но для меня это спасло положение, сделав возможной тесную интеграцию несовместимых систем.

person mdma    schedule 27.04.2010

Я опубликовал рецензию на мой блог с подробным описанием моего недавнего опыта решения этой же проблемы. В общем, вы хотите избежать попыток подключить входной или выходной поток к клиенту на любом языке, поскольку это подразумевает потоки. Вы можете постепенно доставлять данные с помощью обратных вызовов.

person Cliff    schedule 23.04.2010

Как я могу вызвать Foo::print из Java, чтобы вывод отображался на выходе?

Концептуально говоря, способ заставить Foo::print(...) писать в существующий экземпляр Java OutputStream состоит в том, чтобы написать реализацию C++ std::ostream, которая фактически выполняет обратный вызов в Java для выполнения вывода.

Это звучит возможно, но я бы не хотел писать/поддерживать код. Во время выполнения у вас будут вызовы, идущие из Java -> C++ -> Java, и есть много возможностей для совершения ошибок, которые случайно приведут к сбою вашей JVM.

Есть ли способ принудить OutputStream к std::ostream на уровне JNI?

АФАИК нет.

Могу ли я захватить выходные данные в буфер слоя JNI, а затем скопировать его?

Вы имеете в виду что-то примерно такое?

    MyJNIThing m = ...
    int myOstream = m.createMemoryBackedOStream(...); // native method
    ...
    m.someMethodWrapper(... myOStream); // native method
    ...
    byte[] data = m.getCapturedData(myOStream); // native method
    out.write(data);

Вы, вероятно, можете сделать что-то подобное ... в хороший день с попутным ветром.

Но я думаю, что вы действительно должны стремиться исключить код C++, а не пытаться делать все более сложные вещи в JNI. IMO, JNI следует использовать только в крайнем случае, а не в качестве короткого пути, чтобы избежать перекодирования в Java.

person Stephen C    schedule 16.09.2009
comment
Повторная реализация библиотеки на Java невозможна (она большая, зрелая и требовательная к производительности). - person Chris Conway; 17.09.2009
comment
Возможно, тогда вам не следует пытаться вызывать его из Java. Я хочу сказать, что вы, вероятно, создадите много боли для себя и людей, которые должны поддерживать ваш код. - person Stephen C; 17.09.2009
comment
Хотя я согласен с тем, что код JNI сложен, говорить, что его следует избегать, несправедливо. Определенно есть место для JNI, особенно в крупных устаревших проектах, таких как упомянутая операция, и в моем случае сторонние API, которые вы должны использовать для выполнения работы. Это очень правильный вопрос, на который я тоже ищу ответ. - person Cliff; 16.04.2010
comment
@Cliff - тебе тоже удачи. Обратите внимание, что НИКТО еще не предложил. - person Stephen C; 16.04.2010
comment
Удача была вознаграждена мне, так как теперь я сам предлагаю один пример! Смотрите мой ближайший ответ ниже. - person Cliff; 23.04.2010