Avvio di un processo con stdin/stdout/stderr ereditato in Java 6
Domanda
Se avvio un processo tramite Java's ProcessBuilder class, ho pieno accesso ai flussi di ingresso standard, uscita standard ed errori standard di quel processo come Java InputStreams
E OutputStreams
.Tuttavia, non riesco a trovare un modo per connettere perfettamente tali flussi a System.in
, System.out
, E System.err
.
È possibile utilizzare redirectErrorStream()
per ottenerne uno singolo InputStream
che contiene lo standard out e l'errore standard del sottoprocesso, e basta scorrere questo e inviarlo tramite il mio standard out, ma non riesco a trovare un modo per farlo e lasciare che l'utente digiti nel processo, come potrebbe se io utilizzato il C system()
chiamata.
Questo sembra essere possibile in Java SE 7 quando uscirà: mi chiedo solo se ora ci sia una soluzione alternativa.Punti bonus se il risultato di isatty()
nel processo figlio esegue il reindirizzamento.
Soluzione
Dovrai copiare il file Processi out, err e flussi di input nelle versioni di sistema.Il modo più semplice per farlo è utilizzare il file IOUtils classe dal pacchetto Commons IO.IL metodo di copia sembra essere quello di cui hai bisogno.Le chiamate al metodo di copia dovranno trovarsi in thread separati.
Ecco il codice 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();
Altri suggerimenti
Una variazione della risposta di John che compila e non richiede l'utilizzo di 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();
}
Per System.in
utilizza il seguente pipein()
invece di pipe()
pipein(System.in, p.getOutputStream());
Implementazione:
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();
}