Run the subprocess to correctly provide input and output in Java

I use the runtime exec () method to create subprocesses in Java However, since the subprocess is an interactive program, I need to provide input for it when needed In addition, I need to display the output of the child process How can I do this in the simplest way?

I use streamgobbler and process Getinputstream() displays the program output However, I don't know how to identify when the program is waiting for input and when to use proc Getoutputstream provides input How can I do this?

Solution

You need to copy the input and output between the subprocess flow and the system flow (system. In, system. Out, and system. ERR) This is related to my recent query The best solution I have found so far is:

import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.FileChannel;

class StreamCopier implements Runnable {
    private InputStream in;
    private OutputStream out;

    public StreamCopier(InputStream in,OutputStream out) {
        this.in = in;
        this.out = out;
    }

    public void run() {
        try {
            int n;
            byte[] buffer = new byte[4096];
            while ((n = in.read(buffer)) != -1) {
                out.write(buffer,n);
                out.flush();
            }
        }
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

class InputCopier implements Runnable {
    private FileChannel in;
    private OutputStream out;

    public InputCopier(FileChannel in,OutputStream out) {
        this.in = in;
        this.out = out;
    }

    public void run() {
        try {
            int n;
            ByteBuffer buffer = ByteBuffer.allocate(4096);
            while ((n = in.read(buffer)) != -1) {
                out.write(buffer.array(),n);
                out.flush();
            }
            out.close();
        }
        catch (AsynchronousCloseException e) {}
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

public class Test {
    private static FileChannel getChannel(InputStream in)
            throws NoSuchFieldException,illegalaccessexception {
        Field f = FilterInputStream.class.getDeclaredField("in");
        f.setAccessible(true);
        while (in instanceof FilterInputStream)
            in = (InputStream)f.get((FilterInputStream)in);
        return ((FileInputStream)in).getChannel();
    }

    public static void main(String[] args)
            throws IOException,InterruptedException,NoSuchFieldException,illegalaccessexception {
        Process process = Runtime.getRuntime().exec("sh -i +m");
        Thread outThread = new Thread(new StreamCopier(
                process.getInputStream(),System.out));
        outThread.start();
        Thread errThread = new Thread(new StreamCopier(
                process.getErrorStream(),System.err));
        errThread.start();
        Thread inThread = new Thread(new InputCopier(
                getChannel(system.in),process.getOutputStream()));
        inThread.start();
        process.waitFor();
        system.in.close();
        outThread.join();
        errThread.join();
        inThread.join();
    }
}

The tricky part here is from system In to extract a channel Without this, you will not be able to interrupt the thread reading input when the child process terminates

This method has a serious disadvantage: turn off system After in, you can no longer read it My current solution is to use a single input redirection thread for all child processes

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>