What I want to do is, launch a .exe console program with Java, and use Java to manipulate the input and output streams from the console window. I know I can get the input and outpu开发者_开发知识库t streams from an application, and this is how I am currently doing it:
try {
process = Runtime.getRuntime().exec("C:\\Users\\Owner\\Documents\\testApp\\console.exe");
} catch (IOException e1) {
e1.printStackTrace();
return;
}
stdin = process.getOutputStream();
stdout = process.getInputStream();
Then, I can use a BufferedReader to show output that the .exe would normally display, however I cannot figure out how to pass input from the Java application console program to the actual .exe input stream. I need some help with how to do this.
Edit: Ok, I now have this, which works concurrently; however, I can't seem to get any output related to any input I take from the Java console window.
new Thread(new Runnable() {
public void run() {
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
try {
while ((line = br.readLine()) != null) {
System.out.println("[OUT] " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = System.in.read(buffer)) != -1) {
for(int i = 0; i < buffer.length; i++) {
int intValue = new Byte(buffer[i]).intValue();
if (intValue == 0) {
bytesRead = i;
break;
}
}
// for some reason there are 2 extra bytes on the end
stdin.write(buffer, 0, bytesRead-2);
System.out.println("[IN] " + new String(buffer, 0, bytesRead-2) + " [/IN]");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
You can create another thread that constantly reads from Java's console, re-writing it to the process's standard input:
new Thread(
new Runnable() {
public void run() {
try {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = System.in.read(buffer)) != -1) {
process.getOutputStream().write(buffer, 0, bytesRead);
}
} catch (IOException e) {
// Do something with the error...
}
}
}
).start();
Firstly, you need to be consuming stdout/stderr concurrently (via separate threads). Otherwise you can block your spawned process since you're not consuming its output. See this answer for more details.
To write to the process, I would wrap the stdin
OutputStream
with a BufferedWriter
, and simply write to that from System.in
Use the ProcessBuilder API. It has the very convenient option to join stderr and stdout streams, so you don't have to use multiple threads to read from the streams.
redirectErrorStream(true)
is your friend here.
If you want to pass data to the process:
proc.getOutputStream().write(allmydata);
To read data:
proc.getInputStream().read(byteBuffer);
Please be aware of the following: If the input data is more than the process can buffer, and if the process already filled its output buffer, and you do not read from the output buffer, you will have a classic deadlock situation. In this case you either have to read output of the process in a separate process and buffer it yourself, or you make the process redirecting the data to a temporary file first, and read this in in a second step. The first variant is more performant, but the second is more easy to understand and might also be a valid option if there is much of data and performance doesn't count.
精彩评论