Saltar al contenido

ProcessBuilder: reenvío de stdout y stderr de procesos iniciados sin bloquear el hilo principal

Ya no necesitas investigar más por otras páginas ya que estás al espacio adecuado, tenemos la respuesta que deseas y sin liarte.

Solución:

Usar ProcessBuilder.inheritIOestablece que el origen y el destino de la E/S estándar del subproceso sean los mismos que los del proceso Java actual.

Process p = new ProcessBuilder().inheritIO().command("command1").start();

Si Java 7 no es una opción

public static void main(String[] args) throws Exception 
    Process p = Runtime.getRuntime().exec("cmd /c dir");
    inheritIO(p.getInputStream(), System.out);
    inheritIO(p.getErrorStream(), System.err);



private static void inheritIO(final InputStream src, final PrintStream dest) 
    new Thread(new Runnable() 
        public void run() 
            Scanner sc = new Scanner(src);
            while (sc.hasNextLine()) 
                dest.println(sc.nextLine());
            
        
    ).start();

Los subprocesos morirán automáticamente cuando finalice el subproceso, porque src EOF.

A la única forma de entrar Java 6 o anterior es con un supuesto StreamGobbler (que ha comenzado a crear):

StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR");

// any output?
StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), "OUTPUT");

// start gobblers
outputGobbler.start();
errorGobbler.start();

private class StreamGobbler extends Thread 
    InputStream is;
    String type;

    private StreamGobbler(InputStream is, String type) 
        this.is = is;
        this.type = type;
    

    @Override
    public void run() 
        try 
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null)
                System.out.println(type + "> " + line);
        
        catch (IOException ioe) 
            ioe.printStackTrace();
        
    

Para Java 7, vea la respuesta de Evgeniy Dorofeev.

Una solución flexible con Java 8 lambda que le permite proporcionar una Consumer que procesará la salida (por ejemplo, registrarla) línea por línea. run() es una sola línea sin excepciones marcadas lanzadas. Como alternativa a la implementación Runnablese puede extender Thread en cambio, como sugieren otras respuestas.

class StreamGobbler implements Runnable 
    private InputStream inputStream;
    private Consumer consumeInputLine;

    public StreamGobbler(InputStream inputStream, Consumer consumeInputLine) 
        this.inputStream = inputStream;
        this.consumeInputLine = consumeInputLine;
    

    public void run() 
        new BufferedReader(new InputStreamReader(inputStream)).lines().forEach(consumeInputLine);
    

Luego puede usarlo, por ejemplo, así:

public void runProcessWithGobblers() throws IOException, InterruptedException 
    Process p = new ProcessBuilder("...").start();
    Logger logger = LoggerFactory.getLogger(getClass());

    StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), System.out::println);
    StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), logger::error);

    new Thread(outputGobbler).start();
    new Thread(errorGobbler).start();
    p.waitFor();

Aquí el flujo de salida se redirige a System.out y el flujo de error se registra en el nivel de error por el logger.

Ten en cuenta compartir este enunciado si te ayudó.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *