我正在编写一个通过JNI接口使用C ++库的Java应用程序。 C ++库创建类型为Foo
的对象,这些对象通过JNI正式传递给Java。
假设库具有输出功能
void Foo::print(std::ostream &os)
我有一个Java OutputStream out
。如何从Java调用Foo::print
以便输出显示在out
上?有没有办法将OutputStream
强制转换为JNI层中的std::ostream
?我可以在缓冲区中捕获JNI层的输出,然后将其复制到out
?
答案 0 :(得分:6)
我会实现一个C ++ ostream来缓冲写入(最多一些设置大小),然后通过JNI将这些写入刷新到java OutputStream。
在java端,您既可以使用常规的OutputStream实例,也可以实现缓冲区块的排队(实际上是byte []),以避免线程之间发生任何可能的锁争用。实际输出流仅由另一个线程上的任务使用,该线程从队列中提取块并将它们写入OutpuStream。我不能说在这个详细程度上是否有必要 - 你可能会发现直接写入JNI工作的输出流。
我不与JNI分享其他海报问题,也没有看到使用JNI的任何问题。当然,你的维护者必须知道他们的东西,但就是这样,Java / C ++层的复杂性可以通过文档,示例和测试用例来管理。在过去,我已经实现了一个Java<> COM桥接器,其界面非常繁琐 - 性能,线程或维护都没有问题。
鉴于完全自由的选择,没有JNI,但对我而言,它通过使其他不兼容的系统紧密集成而节省了一天。
答案 1 :(得分:1)
我发布了writeup on my blog详细说明了我最近遇到的同样问题。通常,您希望避免尝试使用任何语言将输入或输出流连接到客户端,因为它意味着线程。您可以使用回调递增地传递数据。
答案 2 :(得分:0)
如何从Java调用Foo :: print 以便输出显示在外面?
从概念上讲,让Foo :: print(...)写入现有Java OutputStream实例的方法是编写一个C ++ std :: ostream实现,该实现实际上对Java进行回调以进行输出。
这听起来有可能,但我不想写/维护代码。在运行时,您将从Java调用 - > C ++ - > 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);
你可以做出类似的工作......在美好的一天伴随着风。
但我认为你应该真正想要消除C ++代码,而不是试图在JNI中做越来越复杂的事情。 IMO,JNI应该只作为最后的手段,而不是捷径,以避免重新编写Java中的内容。