3

I'm executing the cmd process in Native windows from my Java program. I want to be able to view the input and the output of the forked process. However, I don't seem to be able to write anything to it from the Java program.

When I try to write a set of characters onto the command prompt in windows, I'm kind of expecting it to print something to the screen - anything. So, if I give it nonsensical garbage, then it should print that it doesn't understand that command.

However, after writing my garbage String onto the child process's OutputStream in the following code:

Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("cmd");
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
PrintWriter out = new PrintWriter(process.getOutputStream());
String line = null;
out.println("My Garbage String");
while((line = readLine()) != null)
    System.out.println(line);

the program stops where it says while((line = readLine()) != null).

So, the parent process is obviously blocking until the child process gets some input and unblocks and sends that input to the parent process. But, I'm giving the child process some input when I write anything out onto the PrintWriter's println() method, aren't I?

UPDATE

Now, because of some of the answers that were given to me, I decided to clarify what my problem is. I can read output from the command prompt fine. In fact, when I first run it, I get all the same ouput as you would normally get if you typed "cmd" in the command prompt.

For instance, take the following code example:

Process process = Runtime.getRuntime().exec("cmd");
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
PrintWriter out = new PrintWriter(process.getOutputStream());
String line = null;
do
{
    line = in.readLine();
    System.out.println(line);
}while(line!=null)

The output of the code will be the following:

Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.

As you can see, the command prompt is giving my parent process some output. But, while running this in debug mode in my IDE, I find that it just simply stops at the line=in.readLine(); line. So, the child process blocks because there is nothing else to print.

So, when I try to give it some input using its OutputStream property, it doesn't appear to respond. Instead, the program blocks at where line=in.readLine();.

In response to what one poster suggested, the article you mentioned (When Runtime.exec() won't), it only goes over getting output from the OutputStream and ErrorStream properties. It does not mention how I can give it any kind of input other than the initial execution parameters that are given in the form of an array when you run Runtime.exec(args).

To simulate what I wanted to do initially (ie. give it random garbage and have it print that it doesn't understand the command), I could just simply type Runtime.getRumtime().exec("cmd /c random garbage); in my code and run it. But, that isn't what I want to do. I want to communicate with the command prompt after it's already started its execution.

Ultimately, I want to be able to interact with other program that normally requires you to interact with them after execution from a Java program. Yet, if the only time that I can tell it what to do is when I specify its execution parameters, then I won't be able to interact with a separate process using Java in the way that I want to.

If anyone knows how this can be achieved, please tell me. Thanks.

user919860
  • 3,083
  • 4
  • 19
  • 16

5 Answers5

3

StreamGobblers are the way to go google for them. They start in new threads and are reading the output.

A nice article describing how you implement them. When Runtime.exec() won't

2

Here you have a complete sample. Notice that this run the dir command thru the output stream.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

class StreamGobbler extends Thread {
InputStream is;
String type;

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

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();
    }
}
}

public class GoodWindowsExec {
public static void main(String args[]) {


    try {
        String osName = System.getProperty("os.name");
        String[] cmd = new String[1];

        cmd[0] = "cmd.exe";

        Runtime rt = Runtime.getRuntime();

        Process proc = rt.exec(cmd);


        proc.getOutputStream().write("dir \n".getBytes());
        proc.getOutputStream().flush();
        // any error message?
        StreamGobbler errorGobbler = new StreamGobbler(
                proc.getErrorStream(), "ERROR");

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

        // kick them off
        errorGobbler.start();
        outputGobbler.start();

        // any error???
        int exitVal = proc.waitFor();
        System.out.println("ExitValue: " + exitVal);
    } catch (Throwable t) {
        t.printStackTrace();
    }
}
}
  • Here, you're writing to the command prompt by using the OutputStream's write method and writing the command with the line termination character to the method as a set of bytes. I've been using the OutputStream's println method and writing strings without the line termination character and strictly as strings. Was that my problem the whole time??? That the only way that I can write to an external program is to write a series of bytes to the OutputStream's write method? – user919860 Sep 01 '11 at 16:11
1

The Java program controls the input from process.getOutputStream(). If you want to send data to the program, you need to send it from Java.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
0

"The program stops where it says while((line = readLine()) != null)."

The answer is probably in separate issue Java Process with Input/Output Stream (from Luke Woodward's answer):

..the loops while((line = readLine()) != null) only exit when the reader, which reads from the process's standard output, returns end-of-file. This only happens when the process exits. It will not return end-of-file if there happens at present to be no more output from the process. Instead, it will wait for the next line of output from the process and not return until it has this next line.

Try to use one thread to write commands into process.getOutputStream(), and second one to read process.getInputStream().

Community
  • 1
  • 1
vitrilo
  • 1,437
  • 16
  • 20
0

You are confusing things. First of all, the current description is chaotic and you should rewrite it.

Second, do the StreamGobbler as provided in Farmor's answer.

What do you expect from

out.println("My Garbage String"); 
while((line = readLine()) != null)
...

?

It does exactly what it says. Sends a string to external process' input stream than waits at the same input stream for any string to arrive. The one you sent before is of course long gone at the time.

MarianP
  • 2,719
  • 18
  • 17
  • It hasn't been sent as he haven't flushed the stream. –  Aug 31 '11 at 18:36
  • I am not sure if you have to flush it, but it would not change anything. The code he uses does not make sense. – MarianP Aug 31 '11 at 19:14