I have a code that starts a java process (i.e.: executing a compiled java code) via
ProcessBuilder builder = new ProcessBuilder("java", "Sample", "arg1", "arg2");
builder.redirectErrorStream(true);
Process process = builder.start();
Through this, I can basically process the output and errors
OutputStream stdin = process.getOutputStream(); // <- Eh?
InputStream stdout = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
// reader.readLine() blah blah
Now, how can I send input to the stdin? That is, if the code executed by the process has a line that waits for an input as in:
Scanner scan = new Scanner(System.in);
String val = scan.nextLine();
System.out.println(val);
I tried this:
writer.write("I'm from the stdin!.");
writer.flush();
Though nothing happened. The console still waited for an input.
Any thoughts?
EDIT: The question was answered, as accepted below. I'm editing to show the faulty code (which I failed to include btw. Lol).
Before the writer.write() part, I had a
String line;
line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
The Process OutputStream (our point of view) is the STDIN from the process point of view
OutputStream stdin = process.getOutputStream(); // write to this
So what you have should be correct.
My driver (apply your own best practices with try-with-resources statements)
public class ProcessWriter {
public static void main(String[] args) throws Exception {
ProcessBuilder builder = new ProcessBuilder("java", "Test");
builder.directory(new File("C:\\Users\\sotirios.delimanolis\\Downloads"));
Process process = builder.start();
OutputStream stdin = process.getOutputStream(); // <- Eh?
InputStream stdout = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
writer.write("Sup buddy");
writer.flush();
writer.close();
Scanner scanner = new Scanner(stdout);
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
}
}
My application
public class Test {
public static void main(String[] args) throws Exception {
Scanner console = new Scanner(System.in);
System.out.println("heello World");
while(console.hasNextLine()) {
System.out.println(console.nextLine());
}
}
}
Running the driver prints
heello World
Sup buddy
For some reason I need the close(). The flush() alone won't do it.
Edit It also works if instead of the close() you provide a \n.
So with
writer.write("Sup buddy");
writer.write("\n");
writer.write("this is more\n");
writer.flush();
the driver prints
heello World
Sup buddy
this is more
This is an example which maybe can helps someone
import java.io.IOException;
import java.io.File;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
String[] commands = {"C:/windows/system32/cmd.exe"};
ProcessBuilder builder = new ProcessBuilder(commands);
builder.directory(new File("C:/windows/system32"));
Process process = builder.start();
OutputStream stdin = process.getOutputStream();
InputStream stdout = process.getInputStream();
InputStream stderr = process.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
BufferedReader error = new BufferedReader(new InputStreamReader(stderr));
new Thread(() -> {
String read;
try {
while ((read = reader.readLine()) != null) {
System.out.println(read);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
String read;
try {
while ((read = error.readLine()) != null) {
System.out.println(read);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
while (true) {
try {
Scanner scanner = new Scanner(System.in);
writer.write(scanner.nextLine());
writer.newLine();
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
Related
I'm trying to get the terminal width by executing tput cols command and parse the output.
public class Test {
public static void main(String[] args) throws IOException {
Process p = Runtime.getRuntime().exec("tput cols");
String output = new String(p.getInputStream().readAllBytes());
System.out.println(output);
}
}
But it outputs empty string.
However, if I executes it in the terminal I can see the output.
You need to wait for the command to terminate. When you read the output of the tput command, it has not yet terminated and therefore there is not yet any output.
I prefer using class ProcessBuilder rather than class Runtime.
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class PrcBldTs {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder("tput", "cols");
try {
Process p = pb.start();
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = br.readLine();
while (line != null) {
System.out.println(line);
line = br.readLine();
}
int result = p.waitFor();
System.out.println("result = " + result);
}
catch (Exception x) {
x.printStackTrace();
}
}
}
I'm trying to take over another application from java side.
Take over here means to get the output of another application and input the command to it.
The code I have used:
public class ProcessTest implements Runnable{
BufferedReader reader;
PrintWriter writer;
Thread readThread;
boolean terminate = false;
public ProcessTest(){
try{
initialize();
}catch(Exception e){
}
}
public void initialize() throws Exception{
ProcessBuilder builder = new ProcessBuilder("another_application.exe");
builder.redirectErrorStream(true);
Process process = builder.start();
InputStream is = process.getInputStream();
OutputStream os = process.getOutputStream();
InputStreamReader isr = new InputStreamReader(is);
OutputStreamWriter osw = new OutputStreamWriter(os);
reader = new BufferedReader(isr);
writer = new PrintWriter(osw);
readThread = new Thread(this);
readThread.start();
}
#Override
public void run() {
// TODO Auto-generated method stub
while(terminate == false){
int c;
try {
c = reader.read();
if(c == -1){
return;
}
System.out.println(c);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void input(String str){
writer.write(str);
writer.println();
writer.flush();
}
public static void main(String args[]){
ProcessTest obj = new ProcessTest();
Scanner scan = new Scanner(System.in);
while(scan.hasNext()){
String str = scan.nextLine();
obj.input(str);
}
scan.close();
}
}
At the beginning, I can use writer to input command to application and use reader to get its output.
Both reader and writer work fine before I enter a particular command.
After I enter a command to it(The effect of the command: 1, Change the application's status from configuration to running; 2, Plenty of output). The reader keeps working but not the writer. The application fails to show any response from writer's input.
I'm at my wits' end, please kindly tell me the possible reason why such issue happens. The application I'm trying to take over is company internal application so I haven't give you its name.
For research reasons I want to be able to call the Scala REPL in my Java code. To do so I use Java's ProcessBuilder and call the command scala. Although the code nicely returns the welcome message of the scala REPL, the statements that I sent to it do not return any output or errors.
Note that my use of processbuilder is correct, I tested it on other commands and it works. It is specifically Scala that is not giving me any output or errors.
Why isn't Scala giving me any output? Is there a way to make it work?
Here is the short compilable version of my code:
public class CommandEvaluator {
public static void main(String args[]) throws IOException
{
ProcessBuilder pb = new ProcessBuilder("scala.bat");
Process proc = pb.start();
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERR");
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUT");
// kick them off
errorGobbler.start();
outputGobbler.start();
OutputStream outStream = proc.getOutputStream();
PrintWriter pWriter = new PrintWriter(outStream);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) { // REPL
System.out.print("> ");
String stat = br.readLine();
pWriter.println(stat);
pWriter.flush();
}
}
private static class StreamGobbler extends Thread
{
private String type;
private BufferedReader br;
StreamGobbler(InputStream is, String type)
{
this.type = type;
InputStreamReader isr = new InputStreamReader(is);
br = new BufferedReader(isr);
}
#Override
public void run()
{
try
{
String line = null;
while ((line = br.readLine()) != null)
System.out.println(type + ">" + line);
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
}
I want to write a Java program that runs an external "java myprog < input.txt > output.txt" command. The eventual goal is to run this command on two different programs and compare their output similarity from their respective output files.
I think I've read just about every relevant article about using ProcessBuilder to run an external program, and the few entries about handling user input in that external program, but I still can't get things working. From what I have read, I think the best approach is to not run the exact command above, but instead read the input.txt file and feed it byte-by-byte into the Process object, then collect the output and write it to output.txt ... I am 100% open to other options.
I put together the code below based on my readings. It seems to correctly feed input from input.txt into myprog, but when I try to print the external program's output to the console to verify, the program hangs at the point where (surprise) user input is expected in myprog.
I get the same issues with and without the redirectErrorStream(true) line.
I really want this to be in Java since I plan to share the source code with the people whose program outputs I will compare, and they are primarily only familiar with Java.
import java.io.*;
import java.util.*;
public class test7 {
public static void main(String args[]) {
try {
// WANT: "java myprog < input.txt > output.txt"
String inputFile = "input.txt";
String outputFile = "output.txt";
ProcessBuilder pb = new ProcessBuilder("java","myprog");
pb.redirectErrorStream(true); // merge stdout, stderr of process
Process p = pb.start();
// write input to the running program
OutputStream pos = p.getOutputStream();
InputStream fis = new FileInputStream(inputFile);
int read = 0;
while ( (read = fis.read()) != -1) {
pos.write(read);
}
fis.close();
// get output of running program
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
// HANGS HERE WHEN USER INPUT REQUIRED
String lineRead;
while ((lineRead = br.readLine()) != null) {
System.out.println(lineRead);
}
}
catch (IOException e) {
e.printStackTrace();
}
} // end main
}
Here is the content of myprog.java:
import java.io.*;
public class myprog {
public static void main(String args[]) throws IOException {
System.out.println("Hello world!");
System.out.println("Enter something:");
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
// the readLine() command causes ProcessBuilder to hang
cin.readLine();
}
}
And the input.txt file is just
p
The output.txt file should be
Hello world!
Enter something:
I wonder if your problem is partly to do with not using separate threads for reading input and writing output. For instance:
public static void main(String args[]) {
try {
// WANT: "java myprog < input.txt > output.txt"
String inputFile = "input.txt";
String outputFile = "output.txt";
// my ProcessBuilder Strings will be different from yours
ProcessBuilder pb = new ProcessBuilder("java", "-cp", ".;bin;",
"yr12.m04.a.MyProg");
pb.redirectErrorStream(true);
Process p = pb.start();
final OutputStream pos = p.getOutputStream();
final PrintWriter pw = new PrintWriter(pos);
final InputStream fis = new FileInputStream(inputFile);
final BufferedReader fileBr = new BufferedReader(new InputStreamReader(fis));
InputStreamReader isr = new InputStreamReader(p.getInputStream());
final BufferedReader br = new BufferedReader(isr);
new Thread(new Runnable() {
public void run() {
String lineRead;
try {
while ((lineRead = br.readLine()) != null) {
System.out.println(lineRead);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
String lineRead;
while ((lineRead = fileBr.readLine()) != null) {
pw.println(lineRead);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (pw != null) {
pw.close();
}
if (fileBr != null) {
try {
fileBr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
} // end main
Have you thought about using Runtime.getRuntime().exec() instead?
Process proc = Runtime.getRuntime().exec("java myprog "+inputFile+" "+outputFile);
You could include the jar of the 'myprog' and call the main() method yourself. Even more so if myprog is in your domain you could get rid of the main method altogether.
I am trying to write a small Java application that will let me run a Bukkit server off-screen using the Java Process/ProcessBuilder API.
I am able to get the output from the server fine, but the server doesn't respond to commands written by the output stream returned by Process.getOutputStream() (chained to the process input stream).
I tried doing this with my own test code, and it worked. The separate process reading from System.in received the text written to the output stream.
Does Bukkit not listen to System.in or something?
If not, how can that be?
Any ideas?
try {
ProcessBuilder pb = new ProcessBuilder();
File dir = new File("C:/Users/Brian/Desktop/MC-Server/Bukkit-Testing");
pb.directory(dir);
pb.command(new String[] {"java", "-Xincgc", "-Xmx1G", "-jar", "craftbukkit-1.0.1-R1.jar"});
pb.redirectErrorStream(true);
final Process p = pb.start();
InputStream out = p.getInputStream();
BufferedReader r1 = new BufferedReader(new InputStreamReader(out));
String s = null;
new Thread(new Runnable() {
#Override
public void run() {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
Scanner scan = new Scanner(System.in);
String input = null;
while((input=scan.nextLine()) != null) {
if(input.equals("exit")) {
p.destroy();
break;
}
try {
bw.write(input);
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
while((s=r1.readLine()) !=null)
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
}
I don't think Bukkit uses its System.in, so we have to make a workaround.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
public class ConsolePlugin extends JavaPlugin {
public Logger log;
public void onEnable(){
log = this.getLogger();
log.info("BufferedReader has been enabled!");
new Thread(new Runnable(){
public void run(){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while (true){
try {
line=br.readLine();
} catch (Exception e) {e.printStackTrace();}
if (line!=null){
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), line);
System.out.println(line);
}
}
}
}).start();
}
public void onDisable(){
log.info("BufferedReader has been disabled.");
}
}
To send commands:
bw.write(input);
bw.nextLine();
bw.flush();