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