Совместное использование выходных потоков через интерфейс 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
?
Ответы
Ответ 1
Я бы использовал С++ ostream, который буферизует запись (до некоторого заданного размера) перед тем, как очистить эти записи в java OutputStream через JNI.
На стороне java вы можете либо использовать обычный экземпляр OutputStream, либо вы можете реализовать очередь буферов (по существу, byte []), чтобы избежать возможного конфликта между потоками. Реальный выходной поток используется только задачей другого потока, который вытягивает блоки из очереди и записывает их в OutpuStream. Я не могу сказать, нужно ли это или нет на этом уровне детализации - вы вполне можете найти запись непосредственно в выходной поток из JNI.
Я не разделяю другие проблемы с плакатами с JNI и не вижу никаких проблем с использованием JNI для этого. Несомненно, ваши сопровождающие должны знать свои вещи, но об этом, и сложность уровня Java/С++ может управляться с помощью документации, примеров и тестовых примеров. Раньше я реализовал Java < > COM-мост с довольно частым интерфейсом - никаких проблем с производительностью, потоками или поддержкой.
Учитывая абсолютно свободный выбор, JNI не будет, но для меня это спасло день, сделав возможной тесную интеграцию в противном случае несовместимых систем.
Ответ 2
Я разместил запись в моем блоге, подробно рассказывая о моем недавнем опыте с этой же проблемой. В общем, вы хотите избежать попытки подключения входного или выходного потока к клиенту на любом языке, поскольку он подразумевает потоки. Вы можете поэтапно доставлять данные с помощью обратных вызовов.
Ответ 3
Как я могу вызвать Foo:: print из Java так что выход появляется вне?
Концептуально говоря, способ получить Foo:: print (...) для записи в существующий экземпляр Java OutputStream - это написать реализацию С++ std:: ostream, которая фактически выполняет обратный вызов в Java для вывода.
Это звучит возможно, но я бы не хотел писать/поддерживать код. Во время выполнения вы будете иметь вызовы, идущие с Java → С++ → Java, и есть много возможностей для ошибок, которые будут случайным образом разбивать вашу JVM.
Есть ли способ принудить OutputStream в std:: ostream в Уровень JNI?
AFAIK no.
Можно ли записать вывод в буфер слоя JNI, а затем скопировать его в вне дома?
Вы имеете в виду что-то примерно такое?
MyJNIThing m = ...
int myOstream = m.createMemoryBackedOStream(...); // native method
...
m.someMethodWrapper(... myOStream); // native method
...
byte[] data = m.getCapturedData(myOStream); // native method
out.write(data);
Возможно, вы можете сделать что-то вроде этой работы... в хороший день со следующим ветром.
Но я думаю, что вы действительно должны стремиться устранить код на С++, а не пытаться делать все более сложные вещи в JNI. IMO, JNI следует использовать только в качестве последнего средства, а не сокращать время, чтобы избежать перекодировки на Java.