How to use the ProcessBuilder - java

I am trying to use the ProcessBuilder to make java communicate with an external program (Prolog).
I understand how to set the environment variables and have done this.
But I don't understand how I communicate with the process, how I give an input to it, how I get the output from it, how the errors are handled. I believe I need to use an input stream the get the output from prolog, an input stream for the errors from Prolog, and an output stream to give prolog the input. Can somebody tell me how I use these streams to communicate with the program?
Here is what I have so far (let me know if I'm thinking wrong at some point)
ProcessBuilder pb = new ProcessBuilder("gprolog");
//Enviroment variable to disable the gui for prolog
pb.environment().put("LINEDIT", "gui=no");
InputStream in = pb.getInputStream();
InputStream err = pb.getErrorStream();
OutputStream out = pb.getOutputStream();
pb.start();
How do I give a command to prolog after this?

Related

Compiling python program using java file and reading input for python program from the file

I've stored my python code in file and then input is passed through input.txt.
String rollno="13F127";
String file="add";
Process p = Runtime.getRuntime().exec("C:\\Python34\\python C:\\Users\\Raga\\Documents\\"+rollno+"\\"+file+".py < C:\\Users\\Raga\\Documents\\"+rollno+"\\input.txt");
When I run it using jsp file, it takes long time to load and output didnt come. Please help me with this.
I've read this process output using buffered and input reader.
stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
Please help me with this!
Do not use redirections (<, >, or |) with exec!
The redirections are read and translated by the interactive shells (here cmd.exe) where they read a command from their standard input. The shell then opens the relevant files and calls the program with redirected standard streams.
exec just does this last part, and passes the < ...input.text as two arguments to the Python program... that do not processes them and also passes them to the script that do not process them either! So the child tries to read on standard input, and keeps waiting here.
So you should:
use ProcessBuilder which according to Runtime javadoc is now the preferred way to start a process with a modified environment
redirect input stream for the subprocess to the file
More or less:
ProcessBuilder pb = new ProcessBuilder("C:\\Python34\\python",
"C:\\Users\\Raga\\Documents\\"+rollno+"\\"+file+".py");
pb.redirectInput(Redirect.fromFile("C:\\Users\\Raga\\Documents\\"+rollno+"\\input.txt"));
Process p = pb.start();

Java Process getOutputStream to String

Java 8 here. How does one read the data in Process#getOutputStream() into a String? I am trying to run a process from inside Java and hook/capture its STDOUT.
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("consul -v");
String capturedOutput;
OutputStream os = proc.getOutputStream();
capturedOutput = howDoIConvert(os); // <---- ???
Looking for the exact code here (not something vague like baos.toString(codepage). Also interested if I need to close() anything politely.
You read the data from inputStream not from outputStream.
OutputStream is used to pass data to the process.
There are two basic input streams for Process. One is for standard input and can be retrieved with getInputStream() the other is for errors and can be retrieved with getErrorStream()
From javadoc of getInputStream():
Returns the input stream connected to the normal output of the
subprocess
and from getErrorStream()
Returns the input stream connected to the error output of the
subprocess.
Note on streams: from the java program perspective a Process is an external program. When you need to add some input to the external program you write from java to that program (so the output of java program is the input of Process). Instead if the external program writes something you read it (so the output of Process is the input for the java program).
Java Data direction External Process
_____________________________________________________________
write to OutputStream ------------> read from InputStream
read from InputStream <------------ write to OutputStream

Read File to Process Stdin ProcessBuilder

How do I pipe a file into the stdin of a process using ProcessBuilder? The program I am reading the stream from is written in C, but I do not know anything else about it.
Here is the relevant java:
ProcessBuilder pb = new ProcessBuilder("./program").inheritIO();
Process p = pb.start();
DataInputStream din = new DataInputStream(new FileInputStream("./my-file.txt"));
byte[] dinBytes = new byte[din.available()];
din.readFully(dinBytes);
din.close();
OutputStream os = p.getOutputStream();
os.write(dinBytes);
os.close();
int rc = p.waitFor();
System.out.println("RC: " + rc);
Which returns the following error:
java.io.IOException: Stream closed
at java.lang.ProcessBuilder$NullOutputStream.write(ProcessBuilder.java:434)
at java.io.OutputStream.write(OutputStream.java:116)
at java.io.OutputStream.write(OutputStream.java:75)
at Test.main(Test.java:14)
$ input in flex scanner failed
The cause for your error is the call to .inheritIO() when you build the process. This causes all the process's standard file descriptors to be inherited from the Java process. The documentation says:
This is a convenience method. An invocation of the form
pb.inheritIO()
behaves in exactly the same way as the invocation
pb.redirectInput(Redirect.INHERIT)
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT)
And the documentation for redirectInput(Redirect) says:
If the source is Redirect.PIPE (the initial value), then the standard input of a subprocess can be written to using the output stream returned by Process.getOutputStream(). If the source is set to any other value, then Process.getOutputStream() will return a null output stream.
So, basically, the default is that there is a pipeline between the Java process and the built process, so that you can push in data from your program to the process. But you released the standard input of the process from the pipe and let it wait for input from the user console, but then you tried to treat it as if it's still part of the pipe, and get your end of the pipe in order to push data inside. You get a null output stream, and as soon as you try to put something in it, you get an exception.
So you shouldn't make that call. And since you want input from a text file, the easiest thing to do would actually be to redirect that input stream to the file directly. Again, redirecting breaks the pipe - but you won't need it because the redirection actually does what you need:
// Take input from a file, output and error go to user console
pb = new ProcessBuilder("./program")
.redirectInput(new File("./my-file.txt"))
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT);
Process p = pb.start();
int rc = p.waitFor();
An alternative method, in case you want to pipe in more than one file, is to keep the pipe to the process standard input around, but copy the files using Files:
pb = new ProcessBuilder("./program")
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT);
Process p = pb.start();
OutputStream os = p.getOutputStream();
Files.copy( Paths.get("./my-file-1.txt"), os );
Files.copy( Paths.get("./my-file-2.txt"), os );
// more files
os.close();
int rc = p.waitFor();
Regarding the DataInputStream: it is a type of InputStream used for processing binary data that was written from a DataOutputStream - with ints, doubles etc. written in binary form. Of course, like any InputStream, you can read bytes from it as-is. But for that, you don't really need to wrap it in a DataInputStream.

Java spawn new cmd.exe and get the output stream

I'm trying to spawn a new console in java and get the ouput stream.
I tried this way :
Process p = Runtime.getRuntime().exec("cmd.exe /c start");
BufferedWriter out = new BufferedWriter( new OutputStreamWriter(
p.getOutputStream()));
the console spawn but i'm not able to write something on the stream !
The other way :
Process p = Runtime.getRuntime().exec("cmd.exe");
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
p.getOutputStream()));
This time i can write to the stream, but the console is not spawning !
I lack knowledge :/
Thank you in advance.
In your first way you started cmd and it started another process which you have no access too. Don't use this way if you need input/output stream.
The other way is right. Process is running fine. But you didn't provide any input for it. Obtain input stream and send some commands like "cd foo\n", "dir\n". As you can see this is regular stream so it requires to execute the command. Then you can use output stream too.
There are a lot of examples how to do so.

Can't launch external program from Java without closing java app

I'm trying to launch an external program from my java swing app using this:
Process proc = Runtime.getRuntime().exec(cmd);
But the external program never actually gets launched until I close out of my java app...everytime.
It waits to launch only after I have closed out.
the external program I am trying to run is an exe that takes arguments so:
cmd = "externalProgram.exe -v --fullscreen --nowing";
What could possibly be wrong here.
Funny enough it works as expected if i try something simple like:
Process proc = Runtime.getRuntime().exec("notepad.exe");
You may need to read from the process's standard output, or close the standard input, before it will proceed. For reading the output, the problem is that the buffer can get full, blocking the program; for closing the input, the problem is that some programs will try to read data from there if it's available, waiting to do so. One or both of these tricks is very likely to straighten things out for you.
You may also read the error output stream to check it the program is actually being unsuccessfully executed
String cmd = "svn.exe";
Process proc = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line = null;
while((line=reader.readLine())!=null){
System.out.println(line);
}
reader.close();
My console shows
Type 'svn help' for usage.
Which evidently shows the program was executed by Java.

Categories

Resources