17

我正在编写一个通过 JNI 接口使用 C++ 库的 Java 应用程序。C++ 库创建类型为 的对象Foo,这些对象通过 JNI 适当地传递给 Java。

假设库有一个输出函数

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

我有一个 Java OutputStream out。如何Foo::print从 Java 调用以使输出显示在上out?有什么方法可以强制OutputStreamstd::ostreamJNI 层中的 a 吗?我可以在 JNI 层的缓冲区中捕获输出然后将其复制到out吗?

4

3 回答 3

6

在通过 JNI 将这些写入刷新到 java OutputStream 之前,我将实现一个 C++ ostream 来缓冲写入(达到某个设定大小)。

在 java 方面,您可以使用常规的 OutputStream 实例,也可以实现缓冲区块(本质上是 byte[])的排队,以避免线程之间任何可能的锁定争用。真正的输出流仅由另一个线程上的任务使用,该线程从队列中拉出块并将它们写入 OutpuStream。我不能说在这个细节级别上是否有必要 - 您可能会发现直接从 JNI 写入输出流是可行的。

我不与 JNI 分享其他发帖者的担忧,并且不认为为此使用 JNI 有任何问题。当然,你的维护者必须知道他们的东西,但仅此而已,Java/C++ 层的复杂性可以通过文档、示例和测试用例来管理。过去,我已经实现了一个 Java<>COM 桥,它的接口非常健谈——性能、线程或维护都没有问题。

如果有一个完全自由的选择,就没有 JNI,但对我来说,它通过使原本不兼容的系统的紧密集成成为可能,从而挽救了局面。

于 2010-04-27T17:32:53.787 回答
3

在我的博客上发布了一篇文章,详细介绍了我最近遇到的同样问题。通常,您希望避免尝试以任何语言将输入或输出流连接到客户端,因为这意味着线程。您可以使用回调逐步交付数据。

于 2010-04-23T01:52:16.493 回答
0

如何从 Java 调用 Foo::print 以使输出显示在 out 上?

从概念上讲,让 Foo::print(...) 写入现有 Java OutputStream 实例的方法是编写一个 C++ std::ostream 实现,该实现实际上对 Java 进行回调以进行输出。

这听起来可能,但我不想编写/维护代码。在运行时,您将有来自 Java -> C++ -> Java 的调用,并且有很多机会犯错误,这些错误会随机使您的 JVM 崩溃。

有没有办法将 OutputStream 强制转换为 JNI 层中的 std::ostream ?

AFAIK 没有。

我可以在 JNI 层的缓冲区中捕获输出,然后将其复制到 out 中吗?

你的意思大致是这样的吗?

    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 中重新编码内容的捷径。

于 2009-09-16T22:49:26.553 回答