Frage

habe ich eine Klasse in C ++, die kontinuierlich Ausgabetext ein std::ostream als Argument nimmt, um (Trace-Informationen). Ich brauche diesen Text über die Java-Seite zu bekommen so effizient wie möglich. Was ist der beste Weg, dies zu tun? Ich dachte an einen direkten Puffer, aber eine andere Methode, um alle Funktionsaufrufe über Java zu nehmen wäre und dort alle die Verarbeitung zu tun, aber es scheint, dass ich eine Menge JNI Anrufe benötigen würde.

Wenn ein Beispiel für die genaue Implementierungsmethode gezeigt werden könnte, wäre es sehr hilfreich sein, oder wenn ein Code bereits existiert diese (vielleicht Teil eines anderen Projekts) zu tun. Eine weitere Hilfe wäre es anzuschließen direkt mit einem Standard-Java-Streaming-Konstrukt, so dass die gesamte Umsetzung in den Entwickler vollständig transparent war.

(Edit: Ich fand Sharing-Output-Streams über eine JNI-Schnittstelle , die ein Duplikat zu sein scheint, aber nicht wirklich viel helfen - er schien nicht die Antwort zu finden er sucht)

War es hilfreich?

Lösung

Die std :: ostream Klasse erfordert eine std :: streambuf Objekt für seinen Ausgang. Dies wird durch die fstream und string Klassen verwendet, die die Merkmale des Ostream verwenden, indem Sie eine benutzerdefinierte Implementierung der streambuf Klasse bietet.

So können Sie Ihre eigene std :: streambuf Implementierung mit einer überschrieben Überlauf-Methode schreiben, die incomming Zeichen in einem internen String puffern. Alle x Anrufe oder auf eof / Newline einen Java-String erzeugen und die Druckmethode Ihres Java-Print nennen.

Eine unvollständige Beispielklasse:

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);
  }
}

fehlt:

  • Multithread-Unterstützung (die env-Zeiger nur gültig für den JVM Thread)

  • Fehlerbehandlung (Überprüfung für Java Ausnahmen geworfen)

  • Testing (geschrieben innerhalb der letzten 70 min)

  • Native Java-Methode, um die Druckdaten einzustellen.

Auf der Java-Seite benötigen Sie eine Klasse, um die Print zu einem BufferedReader zu konvertieren.

Es haben dort einige Fehler sein, haben nicht genug Zeit, um die Arbeit an ihnen zu verbringen.
Die Klasse erfordert, dass alle Zugang aus dem Thread zu sein, es erstellt wurde.

Hope, das hilft

Hinweis:
Ich habe es mit Visual Studio arbeiten, aber ich kann es nicht mit g an der Arbeit ++ wird zu debuggen versuchen, dass später.
Bearbeiten Es scheint, dass ich für eine offizielle Tutorial auf ausgesehen haben sollte meine Antwort bevore veröffentlichen, die MSDN-Seite zu diesem Thema leitet den String in einer anderen Weise.
Sorry für dieses Posting ohne es besser zu testen :-(.
Eine kleine Korrektur an den obigen Code in einem mehr oder weniger unabhängigen Punkt: Gerade implementieren Input mit einer benutzerdefinierten Klasse und Push-byte [] Arrays anstelle von Strings von c ++
. Die Input hat eine kleine Schnittstelle und ein BufferedReader sollte die meiste Arbeit tun.

Letzte Aktualisierung auf diesem, da im nicht in der Lage, um es an der Arbeit auf Linux zu bekommen, auch mit den Kommentaren auf dem std :: streambuf Klasse des besagt, dass nur Überlauf überschrieben werden.
Diese Implementierung schiebt die rohen Saiten in einen Eingabestrom, der aus von einem anderen Thread gelesen werden kann. Da bin ich zu dumm, um den Debugger arbeitet seine ungetestet zu bekommen, wieder.

//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);
    }
}

Es tut uns so viel Platz verschwenden ^^ (und Zeit: - ().

Andere Tipps

Es klingt, als ob die lieferbaren hier ist eine Unterklasse von ostream. Die unmittelbare Frage, die ich klar sein wollen würde, wird diese Klasse für die Daten Pufferung verantwortlich, bis Java in ruft sie abrufen, oder ist zu erwarten, sofort (synchron?) Gespräch über JNI es weitergeben? Das wird der stärkste Führer sein, wie der Code Gestalt annehmen wird.

Wenn Sie den Text vernünftigerweise erwarten können, als eine Reihe von Linien erscheinen, würde ich darüber nachdenken, sie zu Java präsentiert pro Anruf in einer Zeile: dies scheint ein fairer Kompromiss zwischen der Anzahl der JNI Anrufe und nicht über Gebühr die Weitergabe verzögern auf den Text.

Auf der Java-Seite Ich glaube, Sie befinden sich in einem Reader zu schaffen, damit Kunden den Text über eine vertraute Schnittstelle abholen können, oder vielleicht eine Unterklasse von BufferedReader.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top