Question

I ai une classe en langage C ++ qui prend un std::ostream comme argument pour le texte en continu sortie (informations de trace). Je dois obtenir ce texte sur le côté Java aussi efficacement que possible. Quelle est la meilleure façon de le faire? Je pensais à l'aide d'un tampon direct, mais une autre méthode serait de prendre tous les appels de fonctions à travers Java et faire tout le traitement là-bas, mais il semble que je besoin de beaucoup d'appels JNI.

Si un exemple pourrait être montré de la méthode de mise en œuvre exacte, il serait très utile, ou si un code existe déjà pour le faire (peut-être partie d'un autre projet). Une autre aide serait de le connecter directement à une construction Java standard de diffusion en continu, de sorte que la mise en œuvre entière était complètement transparente pour le développeur.

(Edit: J'ai trouvé Partage de flux de sortie à travers une d'interface JNI qui semble être un double, mais pas vraiment d'une grande aide - il ne semble pas trouver la réponse qu'il cherchait)

Était-ce utile?

La solution

La classe std :: ostream nécessite un objet std :: streambuf pour sa sortie. Il est utilisé par les classes fstream et stringstream, qui utilisent les caractéristiques de ostream en fournissant une implémentation personnalisée de la classe streambuf.

Vous pouvez écrire votre propre std :: mise en œuvre de streambuf avec une méthode de débordement réécrits tampon les caractères incomming dans un StringBuffer interne. Tous les appels x ou sur EOF / saut de ligne génèrent une chaîne de java et appeler la méthode d'impression de votre java PrintStream.

Une classe d'exemple incomplet:

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

manquant:

  • Multithread support (le pointeur de env est valable uniquement pour le fil JVM)

  • Gestion des erreurs (vérification des exceptions java moulinée)

  • Test (écrit dans le dernier 70 min)

  • méthode Java native pour définir la PrintStream.

Du côté java vous avez besoin d'une classe pour convertir le PrintStream à un BufferedReader.

Il doit y avoir quelques bugs là, dépensions pas assez de temps pour travailler sur eux.
La classe exige que tous les accès soit du fil, il a été créé.

Hope this helps

Remarque Je l'ai à travailler avec le studio visuel, mais je ne peux pas obtenir de travailler avec g ++, va essayer de débogage plus tard.
Modifier Il semble que j'aurais cherché un tutoriel plus officiel sur cette bevore affichant ma réponse, la page MSDN sur ce sujet dérive StringBuffer d'une manière différente.
Désolé pour l'affichage sans tester ce mieux :-(.
Une petite correction au code ci-dessus dans une plus ou moins le point sans rapport: Il suffit de mettre en œuvre InputStream avec une classe personnalisée et appuyez sur octet [] au lieu des tableaux de chaînes de c ++
. Le InputStream a une petite interface et un BufferedReader devrait faire la plupart des travaux.

Dernière mise à jour sur celui-ci, depuis im incapable de le faire fonctionner sur linux, même avec les commentaires sur la classe std :: streambuf indiquant que le débordement ne doit être remplacé.
Cette mise en œuvre pousse les cordes premières dans un InputStream, qui peut être lu à partir d'un autre thread. Depuis que je suis trop stupide pour obtenir le débogueur de travail non testé son, encore une fois.

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

Désolé pour perdre beaucoup d'espace ^^ (et le temps: -. ()

Autres conseils

On dirait que le livrable ici est une sous-classe de ostream. La question immédiate que je voudrais être clair sur est, cette classe sera responsable de la mise en mémoire tampon des données jusqu'à ce que Java remet en pour récupérer, ou est-il devrait immédiatement (synchrone?) Appeler via JNI pour le transmettre? Ce sera le guide le plus fort sur la façon dont le code sera façonner.

Si vous pouvez raisonnablement attendre que le texte apparaisse comme une série de lignes, je pense à les présenter à Java en une ligne par appel: cela semble un bon compromis entre le nombre de JNI appelle et ne pas retarder indûment l'adoption sur du texte.

Du côté Java Je pense que vous cherchez à créer un lecteur afin que les clients peuvent prendre le texte via une interface familière, ou peut-être une sous-classe de BufferedReader.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top