2008-09-13 6 views
28

Si je démarre un processus via la classe ProcessBuilder de Java, j'ai un accès complet aux flux d'erreur standard, standard et standard de ce processus en tant que Java InputStreams et OutputStreams. Cependant, je ne peux pas trouver un moyen de connecter de façon transparente ces flux à System.in, System.out, et System.err.Démarrage d'un processus avec stdin/stdout/stderr hérité en Java 6

Il est possible d'utiliser redirectErrorStream() pour obtenir un seul InputStream qui contient la norme de subprocess résultats et les erreurs standard, et la boucle juste par cela et l'envoyer par ma sortie standard, mais je ne peux pas trouver un moyen de le faire et laisser le type d'utilisateur dans le processus, comme il ou elle pourrait si j'ai utilisé l'appel C system().

Cela semble être possible dans Java SE 7 quand il sortira - je me demande simplement s'il existe une solution de contournement maintenant. Points bonus si le résultat de isatty() dans le processus enfant passe par la redirection.

+0

Désolé je ne peux pas aider. – jjnguy

+0

Pas de problème. (Au fait, ce n'est pas moi qui vous ai rabaissé.) –

+0

Hé bien, merci au gars qui m'a non-voté. Et merci, John de ne pas m'avoir rabaissé. – jjnguy

Répondre

15

Vous devrez copier les flux de sortie, d'erreur et d'entrée Process vers les versions du système. La méthode la plus simple consiste à utiliser la classe IOUtils du package Commons IO. Le copy method semble être ce dont vous avez besoin. Les invocations de méthode de copie devront être dans des threads séparés.

Voici le code de base:

// Assume you already have a processBuilder all configured and ready to go 
final Process process = processBuilder.start(); 
new Thread(new Runnable() {public void run() { 
    IOUtils.copy(process.getOutputStream(), System.out); 
} }).start(); 
new Thread(new Runnable() {public void run() { 
    IOUtils.copy(process.getErrorStream(), System.err); 
} }).start(); 
new Thread(new Runnable() {public void run() { 
    IOUtils.copy(System.in, process.getInputStream()); 
} }).start(); 
+4

Pas tout à fait. IOUtils.copy prend InputStream comme premier argument, donc cela ne fonctionnera pas avec getOutputStream. C'est donc IOUtils.copy (process.getInputStream(), System.out); C'est un peu déroutant, car getOutputStream redirige réellement vers le processus. – Eelco

+0

La structure de ceci semble juste, mais je suis également d'accord que les paramètres de IOUtils semblent backwords. le processus.getInputStream() est ce qui devrait être redirigé vers stdout (oui, ça sonne en arrière). Donc, alors que la structure de ce semble bien, les appels à IOUtils semblent faux et maintenant me faire un peu confus ... – titania424

+1

Mauvais. Cela ne fait que ** canaliser ** les données entre les flux d'entrée/sortie du parent et de l'enfant, ne le laisse pas ** les hériter **. Par exemple, même si la commande Java a été démarrée sur un terminal (C isatty() == true, ou System.console()! = Null) l'enfant ne se verra pas être exécuté dans un terminal, car ses flux d'entrée/sortie sont des tuyaux. Ceci est important car certains (la plupart) des programmes se comportent différemment lorsqu'ils sont exécutés dans un terminal. ProcessBuilder.Redirect.INHERIT de Java 7 fonctionne correctement à cet égard. – Tobia

13

Une variante de la réponse de John qui compile et ne vous oblige pas à utiliser Commons IO:

private static void pipeOutput(Process process) { 
    pipe(process.getErrorStream(), System.err); 
    pipe(process.getInputStream(), System.out); 
} 

private static void pipe(final InputStream src, final PrintStream dest) { 
    new Thread(new Runnable() { 
     public void run() { 
      try { 
       byte[] buffer = new byte[1024]; 
       for (int n = 0; n != -1; n = src.read(buffer)) { 
        dest.write(buffer, 0, n); 
       } 
      } catch (IOException e) { // just exit 
      } 
     } 
    }).start(); 
} 
+0

Ne répond pas à la question de System.in. – solotim

+0

Pourquoi pipe (System.in, process.getOutputStream()); ne semble pas fonctionner? –

3

Pour System.in utiliser la pipein() suivante au lieu de pipe()

pipein(System.in, p.getOutputStream()); 

Mise en oeuvre:

private static void pipein(final InputStream src, final OutputStream dest) { 

    new Thread(new Runnable() { 
     public void run() { 
      try { 
       int ret = -1; 
       while ((ret = System.in.read()) != -1) { 
        dest.write(ret); 
        dest.flush(); 
       } 
      } catch (IOException e) { // just exit 
      } 
     } 
    }).start(); 

} 
+0

Cela ne peut pas fonctionner. –

Questions connexes