我有一个C ++类,它以std::ostream
为参数,以便连续输出文本(跟踪信息)。我需要尽可能高效地将这个文本传递给Java端。最好的方法是什么?我正在考虑使用直接缓冲区,但另一种方法是将所有函数调用转移到Java并在那里进行所有处理,但似乎我需要大量的JNI调用。
如果可以显示确切实现方法的示例,那将非常有用,或者如果已经存在某些代码(可能是另一个项目的一部分)。另一个帮助是将它直接连接到标准的Java流构造,这样整个实现对开发人员来说是完全透明的。
(编辑:我发现Sharing output streams through a JNI interface似乎是重复的,但并没有太多的帮助 - 他似乎没有找到他想要的答案)
答案 0 :(得分:4)
std :: ostream类需要一个std :: streambuf对象作为其输出。这由fstream和stringstream类使用,它们通过提供streambuf类的自定义实现来使用ostream的功能。
因此,您可以使用覆盖的溢出方法编写自己的std :: streambuf实现,在内部stringbuffer中缓冲incomming字符。每个x调用或在eof / newline上生成一个java字符串并调用java PrintStream的print方法。
一个不完整的示例类:
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分钟内编写)
设置printstream的原生java方法。
在java端,您需要一个类将PrintStream转换为BufferedReader。
那里必须有一些错误,没有足够的时间来处理它们 该类要求所有访问都来自创建它的线程。
希望这有帮助
注意强>
我让它与visual studio一起工作,但我无法使用g ++,稍后会尝试调试
的修改
似乎我本来应该寻找关于这个bevore发布我的答案的更正式的教程,关于这个主题的MSDN page以不同的方式得到stringbuffer。
很抱歉发布这个没有更好地测试它:-(。
在一个或多或少不相关的点上对上面的代码进行小的修正:只需用自定义类实现InputStream并从c ++推送byte []数组而不是字符串。
InputStream有一个小接口,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);
}
}
很抱歉浪费了这么多空间^^(和时间: - ()。
答案 1 :(得分:0)
听起来好像这里的可交付成果是ostream的子类。我想要明确的直接问题是,这个类是否负责缓冲数据,直到Java调用它来检索,或者是否希望通过JNI立即(同步?)调用它来传递它?这将是代码如何形成的最有力的指南。
如果您可以合理地期望文本显示为一系列行,我会考虑每次调用将它们呈现给Java一行:这似乎是JNI调用次数之间的公平折衷,而不是过度延迟传递在文本上。
在Java方面,我认为您正在考虑创建一个Reader,以便客户可以通过熟悉的界面或BufferedReader的子类来获取文本。