gpt4 book ai didi

java - 使用 JNI 通过 std::ostream 从 C++ 获取文本数据到 Java

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:23:34 25 4
gpt4 key购买 nike

我有一个 C++ 类,它采用 std::ostream 作为参数,以便连续输出文本(跟踪信息)。我需要尽可能高效地将此文本传送到 Java 端。最好的方法是什么?我正在考虑使用直接缓冲区,但另一种方法是将所有函数调用转移到 Java 并在那里进行所有处理,但似乎我需要大量的 JNI 调用。

如果可以显示确切实现方法的示例,那将非常有帮助,或者如果已经存在一些代码可以执行此操作(可能是另一个项目的一部分)。另一个帮助是将它直接连接到标准的 Java 流构造,这样整个实现对开发人员来说是完全透明的。

(编辑:我找到了 Sharing output streams through a JNI interface,这似乎是重复的,但并没有太大帮助——他似乎没有找到他正在寻找的答案)

最佳答案

std::ostream 类的输出需要一个 std::streambuf 对象。这由 fstream 和 stringstream 类使用,它们通过提供 streambuf 类的自定义实现来使用 ostream 的特性。

因此您可以使用覆盖的溢出方法编写自己的 std::streambuf 实现,在内部字符串缓冲区中缓冲传入的字符。每个 x 调用或在 eof/newline 上生成一个 java 字符串并调用 java PrintStream 的打印方法。

一个不完整的示例类:

class JavaStreamBuff : std::streambuf
{
std::stringstream buff;
int size;
jobject handle;
JNIEnv* env

//Ctor takes env pointer for the working thread and java.io.PrintStream
JavaStreamBuff(JNIEnv* env, jobject jobject printStream, int buffsize = 50)
{
handle = env->NewGlobalRef(printStream);
this->env = env;
this->size = size;
}
//This method is the central output of the streambuf class, every charakter goes here
int overflow(int in)
{
if(in == eof || buff.size() == size)
{
std::string blub = buff.str();

jstring do = //magic here, convert form current locale unicode then to java string

jMethodId id = env->(env->GetObjectClass(handle),"print","(java.lang.String)V");

env->callVoidMethod(id,handle,do);

buff.str("");
}
else
{buff<<in;}
}

virtual ~JavaStreamBuff()
{
env->DeleteGlobalRef(handle);
}
}

缺失:

  • 多线程支持(env指针只对jvm线程有效)

  • 错误处理(检查抛出的 java 异常)

  • 测试(在过去 70 分钟内完成)

  • 用于设置打印流的 native java 方法。

在 Java 端,您需要一个类来将 PrintStream 转换为 BufferedReader。

那里一定有一些错误,还没有花足够的时间来处理它们。
该类要求所有访问都来自创建它的线程。

希望对你有帮助

注意
我让它与 visual studio 一起工作,但我无法让它与 g++ 一起工作,稍后会尝试调试它。
编辑似乎我应该在发布我的答案之前寻找更官方的教程,MSDN page在这个主题上以不同的方式派生字符串缓冲区。
很抱歉在没有更好地测试它的情况下发布它:-(。
在一个或多或少不相关的点上对上面的代码进行一个小的更正:只需使用自定义类实现 InputStream 并推送 byte[] 数组而不是来自 C++ 的字符串。
InputStream 有一个小接口(interface),BufferedReader 应该完成大部分工作。

关于这个的最后更新,因为我无法让它在 linux 上工作,即使对 std::streambuf 类的评论指出只有溢出必须被覆盖。
此实现将原始字符串推送到输入流中,其他线程可以从中读取。因为我太笨了,无法让调试器在未经测试的情况下工作。

//The c++ class
class JavaStreamBuf :public std::streambuf
{
std::vector<char> buff;
unsigned int size;
jobject handle;
JNIEnv* env;
public:
//Ctor takes env pointer for the working thread and java.io.PrintStream
JavaStreamBuf(JNIEnv* env, jobject cppstream, unsigned int buffsize = 50)
{
handle = env->NewGlobalRef(cppstream);
this->env = env;
this->size = size;
this->setbuf(0,0);
}
//This method is the central output of the streambuf class, every charakter goes here
virtual int_type overflow(int_type in = traits_type::eof()){
if(in == std::ios::traits_type::eof() || buff.size() == size)
{
this->std::streambuf::overflow(in);
if(in != EOF)
buff.push_back(in);

jbyteArray o = env->NewByteArray(buff.size());
env->SetByteArrayRegion(o,0,buff.size(),(jbyte*)&buff[0]);
jmethodID id = env->GetMethodID(env->GetObjectClass(handle),"push","([B)V");

env->CallVoidMethod(handle,id,o);
if(in == EOF)
env->CallVoidMethod(handle,id,NULL);

buff.clear();
}
else
{
buff.push_back(in);
}

return in;
}

virtual ~JavaStreamBuf()
{
overflow();
env->DeleteGlobalRef(handle);
}

//The java class
/**
*
*/
package jx;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* @author josefx
*
*/
public class CPPStream extends InputStream {

List<Byte> data = new ArrayList<Byte>();
int off = 0;
private boolean endflag = false;
public void push(byte[] d)
{
synchronized(data)
{
if(d == null)
{
this.endflag = true;
}
else
{
for(int i = 0; i < d.length;++i)
{
data.add(d[i]);
}
}
}
}
@Override
public int read() throws IOException
{
synchronized(data)
{

while(data.isEmpty()&&!endflag)
{

try {
data.wait();
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}
}
if(endflag)return -1;
else return data.remove(0);
}
}

抱歉浪费了这么多空间^^(和时间:-()。

关于java - 使用 JNI 通过 std::ostream 从 C++ 获取文本数据到 Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2328090/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com