2010-11-30 23 views
2

Salut les gars. Donc, voici l'affaire. J'ai un programme Java qui exécute un programme C++. Le processus C++ envoie des doubles au programme Java en appelant simplement write sur std :: cout avec un cast de pointeur. Le programme Java utilise getInputStream de Process(), lit 8 octets et les convertit en double en utilisant un décalage d'octets et Double.longBitsToDouble(). Je me suis assuré que les tailles de caractères ainsi que les ordres d'octets correspondent entre les deux applications. Maintenant, bien que cela fonctionne la plupart du temps, une erreur se produit souvent.Java Process Bogue InputStream?

J'ai isolé l'une des erreurs sur une simple séquence d'octets que je semble incapable de transférer correctement. Consultez les extraits suivants:

#include <iostream> 

int main(int argc, char** argv) { 
    long long l = 0x4048e398b90ae1b6; 
    char* ptr = (char*) &l; 
    std::cout.write(ptr, 8); 
    std::cout.flush(); 


    // for (int i = 0; i < 8; ++i) 
    // std::cout.put(ptr[i]); 
    // std::cout.flush() 
} 

Et l'application Java:

public static void main(String[] argv) throws IOException { 
    Process p = Runtime.getRuntime().exec("prog.exe"); 
    InputStream is = p.getInputStream(); 

    for (int i = 0 ; i < 8; ++i) { 
    System.err.print(Long.toHexString(is.read()) + " "); 
    } 
} 

Ce sont des exemples assez simples mais ils serveur pour démontrer mon problème. Quand je cours ceci sur ma machine de Windows 7. Je reçois la sortie Java suivante:

b6 e1 d a b9 98 e3 48 

Le résultat attendu est

b6 e1 a b9 98 e3 48 40 

D'une certaine façon, un octet 0x0D supplémentaire est inséré. Cependant, ce qui est vraiment étrange est que si à l'intérieur de l'application java on peut lire un octet (changer le 8 à 9), nous obtenons

b6 e1 d a b9 98 e3 48 40 

Cela signifie que le InputStream contenait en fait 9 octets de données et une fois que extra 0x0d est supprimé il contient les données correctes.

Qu'en pensez-vous? Comme je l'ai déjà mentionné, cela n'arrive pas souvent, mais quand c'est le cas, c'est désastreux.

Merci à l'avance, zienkikk

Répondre

6

cout est par défaut ouvert en mode texte, ce que je dirais qui se passe est que le caractère 0xa (saut de ligne) est de se converti en une séquence <CRLF> au cours pré-traitement de sortie.

Je ne pense pas qu'il soit possible d'écrire de manière fiable des données binaires à cout (voir here par exemple), donc je convertirais la sortie désirée en texte, et désérialiserais du côté de l'entrée (Java).

+0

Vous pouvez également utiliser un fichier explicite ouvert en mode binaire pour communiquer les données. –

+0

@Karl - oui, je ne savais pas trop comment suggérer que l'OP connecte les flux si ça va comme ça mais c'est une option à coup sûr. –

+0

Merci pour les réponses rapides. C'est exactement ce que l'erreur était.L'utilisation d'un fichier ralentit pour la quantité de données que je transmets, mais puisque ce code est destiné à fonctionner sur une machine Unix, je pense que cela suffira (j'étais trop paresseux pour lancer la machine virtuelle et la tester). Je sais que l'écriture de données binaires sur stdout est un peu ify mais cela semblait être la manière la plus simple d'atteindre le résultat souhaité. – zienkikk

2

Il me semble que votre shell Windows convertit le terminateur de ligne de style UNIX LF (0xA) en CRLF Windows Line Terminator (0xD OxA).

Généralement, il n'est pas recommandé d'écrire des données binaires dans le flux de sortie du programme pour cette raison particulière. Convertissez vos données longues en texte, puis analysez-les du côté Java.

+0

Il n'y a pas de shell impliqué ici. – EJP

+0

@EJP. D'accord. Mon C++ devient de plus en plus rustre. –

3

C++ traduit 0x0A, qui est \ n, en 0x0d0a, qui est \ r \ n. Il y a une méthode pour l'arrêter, ne peut pas vous aider avec ce que c'est. Je n'utiliserais pas iostreams pour les données binaires moi-même, j'utiliserais probablement juste write() ou fwrite().