Подтвердить что ты не робот

Совместное использование выходных потоков через интерфейс 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?

4b9b3361

Ответ 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.