How can I unblock from a Java started process?

2020-05-07 05:08发布

When executing some command(let's say 'x') from cmd line, I get the following message: "....Press any key to continue . . .". So it waits for user input to unblock.

But when I execute the same command ('x') from java:

Process p = Runtime.getRuntime().exec(cmd, null, cmdDir);
// here it blocks and cannot use outputstream to write somnething
p.getOutputStream().write(..);

the code blocks...

I tried to write something into the process's output stream, but how can i do that sice the code never reaches that line ?

标签: java process
8条回答
萌系小妹纸
2楼-- · 2020-05-07 05:20

I think (although can't be certain) that you're talking about Windows rather than Unix?

If so, it's possible that the command line process isn't actually waiting for a key press (or input) on stdin but instead doing the equivalent of the old DOS kbhit() function.

AFAIK there's no way to make that function believe that the keyboard has been pressed without actually pressing a key.

To test this theory, create a text file "input.txt" with some blank lines in it, and run:

foo.exe < input.txt

That will show whether your program is waiting on stdin or on something else.

查看更多
爷、活的狠高调
3楼-- · 2020-05-07 05:20

You should read the ouput and error streams of your subprocess simultaneously. The buffer size of these streams is limited. If one of the buffers gets full the subprocess will block. I think that is what happens in your case.

查看更多
ら.Afraid
4楼-- · 2020-05-07 05:21

I wrote an answer to command line execution at this stackoverflow question.

Yours is a bit more tricky since you probably need to reply.

In your case it might me necessary to give the input stream gobbler something like a reply channel:

 StreamGobbler outputGobbler = new StreamGobbler(
                                    proc.getInputStream(), "OUTPUT", 
                                    proc.getOutputStream());

and make it match a pattern and reply on the given input stream.

while ((line = br.readLine()) != null) {
    System.out.println(type + ">" + line);
    if (line.contains(PRESS_KEY_CONTINUE) {
        ostream.write("y".getBytes("US-ASCII")); 
        System.out.println("< y"); 
    }
}

Hope this helps.

查看更多
狗以群分
5楼-- · 2020-05-07 05:21

Use a PrintWriter to simulate some input:

        Process p = Runtime.getRuntime().exec(cmd, null, cmdDir);
        //consume the proces's input stream
        ........
        // deblock
        OutputStream outputStream = p.getOutputStream();
        PrintWriter pw = new PrintWriter(outputStream);
        pw.write("ok");
        pw.flush();
        int errCode = p.waitFor();
查看更多
欢心
6楼-- · 2020-05-07 05:22

The program doesn't continue because it is blocked expecting input from the user.

An option is to launch the outer process in a separate thread, or use threads sharing the Process p in order to be able to write to its stream.

查看更多
▲ chillily
7楼-- · 2020-05-07 05:30

I think the recommended ray of executing external applications in Java is using a ProcessBuilder. The code looks like

//Launch the program
ArrayList<String> command = new ArrayList<String>();
command.add(_program);
command.add(param1);
...
command.add(param1);

ProcessBuilder builder = new ProcessBuilder(command);
//Redirect error stream to output stream
builder.redirectErrorStream(true);

Process process = null;
BufferedReader br = null;
try{
    process = builder.start();

    InputStream is = process.getInputStream();
    br = new BufferedReader( new InputStreamReader(is));
    String line;

    while ((line = br.readLine()) != null) {
         log.add(line);
    }
}catch (IOException e){
    e.printStackTrace();
}finally{
    try{
        br.close();
    }catch (IOException e){
        e.printStackTrace();
    }
}

The process object has a get[Input/Output/Error]Stream that could be used to interact with the program.

查看更多
登录 后发表回答